219 lines
7.6 KiB
JavaScript
219 lines
7.6 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
const root = new URL('..', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1');
|
|
const read = (path) => readFileSync(join(root, path), 'utf8');
|
|
|
|
const appJson = JSON.parse(read('miniapp/app.json'));
|
|
assert.ok(appJson.pages.includes('pages/manager/dashboard'));
|
|
assert.ok(appJson.pages.includes('pages/manager/business'));
|
|
assert.ok(appJson.pages.includes('pages/manager/operations'));
|
|
assert.ok(appJson.pages.includes('pages/manager/people'));
|
|
assert.ok(appJson.pages.includes('pages/manager/order-create'));
|
|
|
|
const index = read('miniapp/pages/index/index.js') + read('miniapp/pages/index/index.wxml');
|
|
for (const pattern of [
|
|
'/auth/me',
|
|
'showManagerEntry',
|
|
'STORE_ADMIN',
|
|
'TENANT_ADMIN',
|
|
'PLATFORM_ADMIN',
|
|
'openManager',
|
|
'pages/manager/dashboard',
|
|
'门店管理'
|
|
]) {
|
|
assert.match(index, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const dashboard = read('miniapp/pages/manager/dashboard.js')
|
|
+ read('miniapp/pages/manager/dashboard.wxml')
|
|
+ read('miniapp/pages/manager/dashboard.wxss');
|
|
for (const pattern of [
|
|
'/management/stores',
|
|
'/management/stores/${encodedStoreId}/rooms',
|
|
'/management/rooms/${encodeURIComponent(roomId)}/status',
|
|
'/orders?page=1&pageSize=50&storeId=${encodedStoreId}',
|
|
'/management/orders/${encodeURIComponent(orderId)}/actions',
|
|
'/management/orders/${encodeURIComponent(orderId)}/note',
|
|
"method: 'PATCH'",
|
|
'store.operation.write',
|
|
'tenant.manage',
|
|
'canReadUsers',
|
|
'canReadOperations',
|
|
'openPeople',
|
|
'openOperations',
|
|
'openBusiness',
|
|
'changeRoomStatus',
|
|
'toggleRoomConfiguration',
|
|
'activeOrders',
|
|
'selectOrderFilter',
|
|
'manageOrder',
|
|
'addOrderNote',
|
|
'代下单',
|
|
'订单处置',
|
|
'实时房态',
|
|
'近期订单',
|
|
'只读'
|
|
]) {
|
|
assert.match(dashboard, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const orderCreate = read('miniapp/pages/manager/order-create.js')
|
|
+ read('miniapp/pages/manager/order-create.wxml');
|
|
for (const pattern of [
|
|
'/management/stores/${encodeURIComponent(this.data.storeId)}/rooms',
|
|
'/management/members?page=1&pageSize=20&status=ACTIVE',
|
|
'/management/orders/reserve-on-behalf',
|
|
'startAt.toISOString()',
|
|
'endAt.toISOString()',
|
|
'pricingMode',
|
|
'selectMember',
|
|
'授权范围内选择会员',
|
|
'价格由服务端'
|
|
]) {
|
|
assert.match(orderCreate, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const orderRoutes = read('backend/src/routes/order-query.ts')
|
|
+ read('backend/src/routes/order-state.ts')
|
|
+ read('backend/src/routes/order-management.ts')
|
|
+ read('backend/src/routes/pricing.ts');
|
|
for (const pattern of [
|
|
'storeId: z.string()',
|
|
'/app-api/management/orders/:orderId/actions',
|
|
'/app-api/management/orders',
|
|
'/app-api/management/orders/reserve-on-behalf'
|
|
]) {
|
|
assert.match(orderRoutes, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const people = read('miniapp/pages/manager/people.js')
|
|
+ read('miniapp/pages/manager/people.wxml');
|
|
for (const pattern of [
|
|
'/management/members?page=1&pageSize=50',
|
|
'/management/members/${encodeURIComponent(memberId)}',
|
|
'/management/staff?page=1&pageSize=50',
|
|
'selectedMember',
|
|
'maskedLastIp',
|
|
'会员与员工',
|
|
'最近余额流水'
|
|
]) {
|
|
assert.match(people, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const peopleRoutes = read('backend/src/routes/members.ts')
|
|
+ read('backend/src/routes/user-management.ts')
|
|
+ read('backend/src/auth/user-management-repository.ts')
|
|
+ read('backend/src/wallets/member-profile-service.ts');
|
|
for (const pattern of [
|
|
'/app-api/management/members',
|
|
'/app-api/management/members/:id',
|
|
'/app-api/management/staff',
|
|
"userType: 'STAFF'",
|
|
'qipai_order_user_access oa',
|
|
"oa.access_type = 'OWNER'",
|
|
'mo.store_id IN'
|
|
]) {
|
|
assert.match(peopleRoutes, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const mysqlPaginationRepositories = peopleRoutes
|
|
+ read('backend/src/orders/order-query-repository.ts')
|
|
+ read('backend/src/cleaning/cleaning-task-repository.ts');
|
|
assert.doesNotMatch(mysqlPaginationRepositories, /LIMIT \? OFFSET \?/);
|
|
assert.match(mysqlPaginationRepositories, /Math\.trunc/);
|
|
|
|
const operations = read('miniapp/pages/manager/operations.js')
|
|
+ read('miniapp/pages/manager/operations.wxml')
|
|
+ read('miniapp/pages/manager/operations.wxss');
|
|
for (const pattern of [
|
|
'/management/cleaning/tasks?page=1&pageSize=50&storeId=${storeId}',
|
|
'/management/cleaning/statistics?storeId=${storeId}',
|
|
'/management/device-topology?storeId=${storeId}',
|
|
'/management/device-control/door',
|
|
'/management/device-control/power',
|
|
'/management/device-control/socket/switch',
|
|
'cleaning.task.write',
|
|
'device.write',
|
|
'验收通过',
|
|
'驳回补做',
|
|
'免清洁',
|
|
'临时开门',
|
|
'全屋断电'
|
|
]) {
|
|
assert.match(operations, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const operationRoutes = read('backend/src/routes/cleaning.ts')
|
|
+ read('backend/src/routes/devices.ts')
|
|
+ read('backend/src/routes/device-control.ts');
|
|
for (const pattern of [
|
|
'/app-api/management/cleaning/tasks',
|
|
'/app-api/management/cleaning/statistics',
|
|
'/app-api/management/devices',
|
|
'/app-api/management/device-topology',
|
|
'/app-api/management/device-control${suffix}'
|
|
]) {
|
|
assert.match(operationRoutes, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
assert.match(read('backend/src/devices/device-control-service.ts'), /DEVICE_COMMAND_REQUESTED/);
|
|
|
|
const business = read('miniapp/pages/manager/business.js')
|
|
+ read('miniapp/pages/manager/business.wxml')
|
|
+ read('miniapp/pages/manager/business.wxss');
|
|
for (const pattern of [
|
|
'/management/statistics?storeId=${storeId}',
|
|
'/management/group-vouchers/redeem',
|
|
'/management/group-vouchers/redeem-manual',
|
|
'/management/third-party/records?storeId=${storeId}',
|
|
'wx.scanCode',
|
|
'clientRequestId',
|
|
'近 {{item}} 天',
|
|
'在线验券',
|
|
'人工确认核销',
|
|
'券码仅保存哈希与脱敏值'
|
|
]) {
|
|
assert.match(business, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const businessRoutes = read('backend/src/routes/third-party.ts')
|
|
+ read('backend/src/third-party/third-party-service.ts')
|
|
+ read('backend/src/routes/business-statistics.ts')
|
|
+ read('backend/src/operations/business-statistics-repository.ts');
|
|
for (const pattern of [
|
|
'/app-api/management/group-vouchers/redeem',
|
|
'/app-api/management/group-vouchers/redeem-manual',
|
|
'/app-api/management/third-party/records',
|
|
'/app-api/management/statistics',
|
|
'redeemVoucherAsManager',
|
|
'qipai_group_redemptions',
|
|
'qipai_payments',
|
|
'BUSINESS_STATISTICS_FORBIDDEN'
|
|
]) {
|
|
assert.match(businessRoutes, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const routes = read('backend/src/routes/store-room-management.ts');
|
|
for (const pattern of [
|
|
'/app-api/management/stores',
|
|
'/app-api/management/stores/:storeId/rooms',
|
|
'/app-api/management/rooms/:id/status',
|
|
'roomStatusSchema',
|
|
'updateRoomStatus'
|
|
]) {
|
|
assert.match(routes, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
|
|
const repository = read('backend/src/stores/store-room-repository.ts');
|
|
assert.match(repository, /ROOM_STATUS_UPDATED/);
|
|
assert.match(repository, /store\.operation\.read/);
|
|
assert.match(repository, /store\.operation\.write/);
|
|
assert.match(repository, /JSON\.stringify\(metadata\)/);
|
|
|
|
const migration = read('database/migrations/2026081001_m08c_staff_management_access.up.sql');
|
|
assert.match(migration, /r\.code = 'STAFF'/);
|
|
assert.match(migration, /store\.operation\.read/);
|
|
|
|
console.log('PASS: M08-C manager/staff miniapp exposes scoped rooms, order handling and on-behalf booking.');
|