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/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', 'openPeople', '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 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.');