From 40905cbd04c2e332cd4bc2b9e0c5b3e1da9cccfa Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期一, 30 三月 2026 08:17:32 +0800
Subject: [PATCH] feat: complete rsf-design phase 1 integration

---
 rsf-design/tests/system-role-scope-contract.test.mjs |  218 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 204 insertions(+), 14 deletions(-)

diff --git a/rsf-design/tests/system-role-scope-contract.test.mjs b/rsf-design/tests/system-role-scope-contract.test.mjs
index 30c293e..dd8b2af 100644
--- a/rsf-design/tests/system-role-scope-contract.test.mjs
+++ b/rsf-design/tests/system-role-scope-contract.test.mjs
@@ -1,21 +1,211 @@
 import assert from 'node:assert/strict'
+import fs from 'node:fs'
 import test from 'node:test'
-import {
-  buildScopeTreeNodes,
-  buildScopeSavePayload,
-  SCOPE_TYPES
-} from '../src/views/system/role/roleScope.config.js'
 
-test('menu scope nodes preserve backend ids for save', () => {
-  const tree = buildScopeTreeNodes(SCOPE_TYPES.menu, [{ id: 1, label: '绯荤粺绠$悊' }])
-  assert.equal(tree[0].id, 1)
+import {
+  buildRoleDialogModel,
+  buildRolePageQueryParams,
+  buildRoleSavePayload,
+  buildRoleScopeSubmitPayload,
+  buildRoleSearchParams,
+  getRoleScopeConfig,
+  normalizeRoleScopeTreeData,
+  normalizeRoleListRow,
+  createRoleSearchState
+} from '../src/views/system/role/rolePage.helpers.js'
+import { resolveBackendMenuTitle } from '../src/utils/backend-menu-title.js'
+
+const rolePermissionDialogSource = fs.readFileSync(
+  new URL('../src/views/system/role/modules/role-permission-dialog.vue', import.meta.url),
+  'utf8'
+)
+const roleEditDialogSource = fs.readFileSync(
+  new URL('../src/views/system/role/modules/role-edit-dialog.vue', import.meta.url),
+  'utf8'
+)
+const roleIndexSource = fs.readFileSync(
+  new URL('../src/views/system/role/index.vue', import.meta.url),
+  'utf8'
+)
+
+test('buildRoleSearchParams keeps real role search fields', () => {
+  assert.deepEqual(
+    buildRoleSearchParams({
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 1,
+      condition: 'admin'
+    }),
+    {
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 1,
+      condition: 'admin'
+    }
+  )
 })
 
-test('scope save payload is delegated per scope type', () => {
-  const payload = buildScopeSavePayload(SCOPE_TYPES.menu, {
-    roleId: 9,
-    selectedIds: [1, 2],
-    authType: 0
+test('buildRolePageQueryParams merges paging and search fields', () => {
+  assert.deepEqual(
+    buildRolePageQueryParams({
+      current: 3,
+      size: 20,
+      name: '绠$悊鍛�'
+    }),
+    {
+      current: 3,
+      pageSize: 20,
+      name: '绠$悊鍛�'
+    }
+  )
+})
+
+test('buildRoleDialogModel normalizes backend role data into the form model', () => {
+  assert.deepEqual(
+    buildRoleDialogModel({
+      id: 7,
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 0
+    }),
+    {
+      id: 7,
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 0
+    }
+  )
+})
+
+test('buildRoleSavePayload submits backend role fields', () => {
+  assert.deepEqual(
+    buildRoleSavePayload({
+      id: 7,
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 1
+    }),
+    {
+      id: 7,
+      name: '绠$悊鍛�',
+      code: 'R_ADMIN',
+      memo: '鏍稿績瑙掕壊',
+      status: 1
+    }
+  )
+})
+
+test('normalizeRoleListRow exposes table friendly fields', () => {
+  const normalized = normalizeRoleListRow({
+    id: 7,
+    name: '绠$悊鍛�',
+    code: 'R_ADMIN',
+    memo: '鏍稿績瑙掕壊',
+    status: 1,
+    createTime: '2025-03-28 10:00:00',
+    updateTime: '2025-03-28 11:00:00'
   })
-  assert.equal(payload.id, 9)
+
+  assert.equal(normalized.name, '绠$悊鍛�')
+  assert.equal(normalized.statusBool, true)
+  assert.equal(normalized.statusText, '姝e父')
+  assert.equal(normalized.statusType, 'success')
+  assert.equal(normalized.createTimeText, '2025-03-28 10:00:00')
+  assert.equal(normalized.updateTimeText, '2025-03-28 11:00:00')
+})
+
+test('buildRoleScopeSubmitPayload normalizes checked keys for backend scope update', () => {
+  assert.deepEqual(
+    buildRoleScopeSubmitPayload(7, ['1', 2], ['3']),
+    {
+      id: 7,
+      menuIds: {
+        checked: [1, 2],
+        halfChecked: [3]
+      }
+    }
+  )
+})
+
+test('getRoleScopeConfig resolves the four backend scope contracts', () => {
+  assert.deepEqual(getRoleScopeConfig('menu'), {
+    scopeType: 'menu',
+    title: '缃戦〉鏉冮檺',
+    listUrl: '/role/scope/list',
+    treeUrl: '/menu/tree'
+  })
+  assert.deepEqual(getRoleScopeConfig('warehouse'), {
+    scopeType: 'warehouse',
+    title: '浠撳簱鏉冮檺',
+    listUrl: '/roleWarehouse/scope/list',
+    treeUrl: '/menuWarehouse/tree'
+  })
+  assert.throws(() => getRoleScopeConfig('invalid'), /Unsupported scope type/i)
+})
+
+test('normalizeRoleScopeTreeData folds menu auth buttons into child nodes', () => {
+  const tree = normalizeRoleScopeTreeData('menu', [
+    {
+      id: 1,
+      name: 'menu.role',
+      type: 0,
+      children: [
+        {
+          id: 2,
+          name: 'Query Role',
+          type: 1,
+          authority: 'system:role:list'
+        }
+      ]
+    }
+  ])
+
+  assert.equal(tree[0].label, 'menus.role')
+  assert.equal(tree[0].children[0].isAuthButton, true)
+  assert.equal(tree[0].children[0].authMark, 'system:role:list')
+})
+
+test('resolveBackendMenuTitle translates legacy backend menu keys into readable labels', () => {
+  assert.equal(resolveBackendMenuTitle('menu.role'), '瑙掕壊绠$悊')
+  assert.equal(resolveBackendMenuTitle('menus.aiParam'), 'AI 鍙傛暟')
+  assert.equal(resolveBackendMenuTitle('AI绠$悊涓績'), 'AI绠$悊涓績')
+})
+
+test('role permission dialog only loads the active scope instead of all scopes together', () => {
+  assert.match(rolePermissionDialogSource, /ensureScopeLoaded\(activeScopeType\.value, \{ force: true \}\)/)
+  assert.doesNotMatch(rolePermissionDialogSource, /loadAllScopeData/)
+})
+
+test('role permission dialog keeps scope tree search and readable labels', () => {
+  assert.match(rolePermissionDialogSource, /placeholder="鎼滅储鏉冮檺鏍�"/)
+  assert.match(rolePermissionDialogSource, /reloadSelection: false/)
+  assert.match(rolePermissionDialogSource, /resolveBackendMenuTitle/)
+})
+
+test('role edit dialog keeps code optional to match the backend contract', () => {
+  assert.match(roleEditDialogSource, /name: \[\{ required: true, message: '璇疯緭鍏ヨ鑹插悕绉�'/)
+  assert.doesNotMatch(roleEditDialogSource, /code: \[\{ required: true, message: '璇疯緭鍏ヨ鑹茬紪鐮�'/)
+})
+
+test('role page uses semantic auth aliases so backend permissions render actions', () => {
+  assert.match(roleIndexSource, /v-auth=\"'add'\"/)
+  assert.match(roleIndexSource, /v-auth=\"'delete'\"/)
+  assert.match(roleIndexSource, /v-auth=\"'query'\"/)
+  assert.match(roleIndexSource, /auth: 'edit'/)
+  assert.match(roleIndexSource, /auth: 'delete'/)
+})
+
+test('createRoleSearchState exposes the role search form model', () => {
+  assert.deepEqual(createRoleSearchState(), {
+    name: '',
+    code: '',
+    memo: '',
+    status: void 0,
+    condition: ''
+  })
 })

--
Gitblit v1.9.1