feat: rename app to Qiyun and refine Tiangong rituals and UI

This commit is contained in:
zhouzhibo committed 2026-11-03 00:16:16 +08:00
1 parent 7871114c50
commit df84a4c130
32 files changed
+482 -130

No files matched your search

+125 -5
View File
@@ -15,11 +15,11 @@ const { createTiangongStore } = load('src/utils/tiangongStore.ts', { './tiangong
const defer = () => { let resolve, reject; const promise = new Promise((ok, fail) => { resolve = ok; reject = fail }); return { promise, resolve, reject } }
function harness() {
let key = 'account-a', time = 1000, rows = [{ id: 81, name: '财神', holdingId: 726, active: true, incenseCount: 7, days: 3 }]
let loader = async () => rows, offer = async () => ({ id: 99 })
let loader = async () => rows, offer = async () => ({ id: 99 }), lifecycle = async () => ({ id: 101 }), dedicate = async () => ({ id: 100 })
const calls = []
const store = createTiangongStore({ key: () => key, now: () => time, resolve: name => name === '财神' ? 'wealth' : undefined,
load: () => loader(), offer: (...args) => { calls.push(args); return offer(...args) }, dedicate: async (...args) => { calls.push(args); return { id: 100 } } })
return { store, calls, key: value => { key = value }, time: value => { time = value }, rows: value => { rows = value }, load: value => { loader = value }, offer: value => { offer = value } }
load: () => loader(), offer: (...args) => { calls.push(args); return offer(...args) }, lifecycle: (...args) => { calls.push(args); return lifecycle(...args) }, dedicate: (...args) => { calls.push(args); return dedicate(...args) } })
return { store, calls, key: value => { key = value }, time: value => { time = value }, rows: value => { rows = value }, load: value => { loader = value }, offer: value => { offer = value }, lifecycle: value => { lifecycle = value }, dedicate: value => { dedicate = value } }
}
test('真实状态不预置财神,按后端持有ID提交,后端确认后才计数', async () => {
const h = harness()
@@ -29,7 +29,7 @@ test('真实状态不预置财神,按后端持有ID提交,后端确认后才
const request = h.store.incense('wealth')
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 7)
assert.equal(h.store.snapshot().deities.wealth.lit, false)
assert.equal(h.calls[0][0], 726); assert.equal(h.calls[0][1], 2)
assert.equal(h.calls[0][0], 726); assert.equal(h.calls[0][1], 1)
response.resolve({ id: 10 }); await request
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 8)
assert.equal(h.store.snapshot().deities.wealth.incenseUntil, 16000)
@@ -101,8 +101,128 @@ test('祈愿和任意姓名回向去空白提交,不携带功德或注册收
const h = harness(); await h.store.refresh()
await h.store.wish('wealth', ' 愿顺遂 ')
await h.store.dedicate('wealth', ' 家人 ', ' 平安 ')
assert.deepEqual(h.calls, [[726, 3, '愿顺遂'], [726, '家人', '平安']])
assert.deepEqual(h.calls, [[726, 2, '愿顺遂'], [726, '家人', '平安']])
assert.equal(h.store.snapshot().deities.wealth.latestPrayer.prayerContent, '愿顺遂')
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationTarget, '家人')
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationContent, '平安')
await assert.rejects(h.store.wish('wealth', ' '), /愿望/)
await assert.rejects(h.store.dedicate('wealth', '', '祝愿'), /回向对象/)
assert.equal(h.calls.length, 2)
})
test('最新祈愿回向随查询加载,失效或账号切换清空,不影响其他神仙', async () => {
const h = harness()
const row = { id: 81, name: '财神', holdingId: 726, active: true, incenseCount: 0, days: 1,
latestPrayer: { offeringId: 10, prayerContent: '已保存愿望' },
latestDedication: { offeringId: 11, dedicationTarget: '众生', dedicationContent: null } }
h.rows([row]); await h.store.refresh()
const first = h.store.snapshot().deities
assert.equal(first.wealth.latestPrayer.prayerContent, '已保存愿望')
assert.equal(first.wealth.latestDedication.dedicationTarget, '众生')
assert.equal(first.wealth.latestDedication.dedicationContent, null)
assert.equal(first.wenchang.latestPrayer, undefined)
first.wealth.latestPrayer.prayerContent = '修改快照不污染缓存'
assert.equal(h.store.snapshot().deities.wealth.latestPrayer.prayerContent, '已保存愿望')
h.rows([{ ...row, latestPrayer: null, latestDedication: null }]); await h.store.refresh(true)
assert.equal(h.store.snapshot().deities.wealth.latestPrayer, null)
assert.equal(h.store.snapshot().deities.wealth.latestDedication, null)
h.rows([row]); await h.store.refresh(true)
h.key('account-b')
assert.equal(h.store.snapshot().deities.wealth.latestPrayer, undefined)
assert.equal(h.store.snapshot().deities.wealth.latestDedication, undefined)
})
test('祈愿确认后才更新回显,失败和账号切换不写入旧账号内容', async () => {
const h = harness(); await h.store.refresh()
const response = defer(); h.offer(() => response.promise)
const request = h.store.wish('wealth', '待确认的愿望')
assert.equal(h.store.snapshot().deities.wealth.latestPrayer, null)
response.resolve({ id: 105 }); await request
assert.equal(h.store.snapshot().deities.wealth.latestPrayer.prayerContent, '待确认的愿望')
h.offer(async () => { throw new Error('提交失败') })
await assert.rejects(h.store.wish('wealth', '失败愿望'), /提交失败/)
assert.equal(h.store.snapshot().deities.wealth.latestPrayer.prayerContent, '待确认的愿望')
const pending = defer(); h.offer(() => pending.promise)
const sending = h.store.wish('wealth', '旧账号愿望')
h.key('account-b'); h.store.snapshot()
pending.resolve({ id: 106 }); await assert.rejects(sending, /登录状态/)
assert.equal(h.store.snapshot().deities.wealth.latestPrayer, undefined)
})
test('回向成功后可回显空祝愿,失败不覆盖已保存对象', async () => {
const h = harness(); await h.store.refresh()
await h.store.dedicate('wealth', '家人', '平安')
h.dedicate(async () => { throw new Error('提交失败') })
await assert.rejects(h.store.dedicate('wealth', '失败对象', ''), /提交失败/)
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationTarget, '家人')
const response = defer(); h.dedicate(() => response.promise)
const sending = h.store.dedicate('wealth', '众生', '')
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationContent, '平安')
response.resolve({ id: 101 }); await sending
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationTarget, '众生')
assert.equal(h.store.snapshot().deities.wealth.latestDedication.dedicationContent, '')
})
test('送神和重新请神使用独立流水,成功后才改变状态且保留次数', async () => {
const h = harness(); await h.store.refresh()
const response = defer(); h.lifecycle(() => response.promise)
const sending = h.store.sendOff('wealth')
assert.equal(h.store.snapshot().deities.wealth.unlocked, true)
await assert.rejects(h.store.sendOff('wealth'), /提交/)
await assert.rejects(h.store.incense('wealth'), /提交/)
response.resolve({ id: 102 }); await sending
const stopped = h.store.snapshot().deities.wealth
assert.equal(stopped.unlocked, false); assert.equal(stopped.canInvite, true)
assert.equal(stopped.incenseCount, 7); assert.equal(stopped.incenseUntil, 0)
assert.equal(mock.hasBoundDeity(h.store.snapshot()), true)
await assert.rejects(h.store.wish('wealth', '愿顺遂'), /绑定/)
h.lifecycle(async () => ({ id: 103 }))
await h.store.invite('wealth')
assert.equal(h.store.snapshot().deities.wealth.unlocked, true)
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 7)
assert.deepEqual(h.calls, [[726, 2], [726, 1]])
})
test('刷新后只允许已送神持有关系重新请神,失败及账号切换不伪造成功', async () => {
const h = harness()
h.rows([{ id: 81, name: '财神', holdingId: 726, holdingStatus: 0, active: false, incenseCount: 7 }])
await h.store.refresh(); assert.equal(h.store.snapshot().deities.wealth.canInvite, true)
h.lifecycle(async () => { throw new Error('设备已解绑') })
await assert.rejects(h.store.invite('wealth'), /设备已解绑/)
assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
const response = defer(); h.lifecycle(() => response.promise)
const sending = h.store.invite('wealth'); h.key('account-b'); h.store.snapshot()
response.resolve({ id: 12 }); await assert.rejects(sending, /登录状态/)
assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
for (const status of [undefined, 1, 3]) {
h.rows([{ id: 81, name: '财神', holdingId: 726, holdingStatus: status, active: false }])
await h.store.refresh(true)
await assert.rejects(h.store.invite('wealth'), /当前状态/)
}
})
test('回向对象允许255字,祝愿可空;上香在途不能送神', async () => {
const h = harness(); await h.store.refresh()
await h.store.dedicate('wealth', '甲'.repeat(255), '')
await assert.rejects(h.store.dedicate('wealth', '甲'.repeat(256), ''), /回向对象/)
await assert.rejects(h.store.dedicate('wealth', '甲', '愿'.repeat(501)), /500/)
const response = defer(); h.offer(() => response.promise)
const sending = h.store.incense('wealth')
await assert.rejects(h.store.sendOff('wealth'), /提交/)
response.resolve({ id: 23 }); await sending
assert.equal(h.store.snapshot().deities.wealth.incenseCount, 8)
})
test('送神失败保留供奉状态,无效流水不显示成功,晚到列表不撤销已送神', async () => {
const h = harness(); await h.store.refresh()
h.lifecycle(async () => { throw new Error('网络失败') })
await assert.rejects(h.store.sendOff('wealth'), /网络失败/)
assert.equal(h.store.snapshot().deities.wealth.unlocked, true)
h.lifecycle(async () => ({ id: 0 }))
await assert.rejects(h.store.sendOff('wealth'), /有效记录/)
assert.equal(h.store.snapshot().deities.wealth.unlocked, true)
const read = defer(); h.load(() => read.promise)
const refreshing = h.store.refresh(true)
h.lifecycle(async () => ({ id: 15 })); await h.store.sendOff('wealth')
read.resolve([{ id: 81, name: '财神', holdingId: 726, active: true, incenseCount: 7 }]); await refreshing
assert.equal(h.store.snapshot().deities.wealth.unlocked, false)
assert.equal(h.store.snapshot().deities.wealth.canInvite, true)
})