feat: 统一账户角色展示并优化资源页面
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"contract:sync": "node scripts/sync-backend-contract.mjs",
|
||||
"contract:check": "node scripts/check-backend-contract.mjs",
|
||||
"resource-pages:check": "node scripts/check-resource-pages.mjs",
|
||||
"account-roles:check": "node scripts/check-account-role-presentation.mjs",
|
||||
"audit:platform": "node scripts/check-backend-contract.mjs",
|
||||
"lint": "biome lint .",
|
||||
"lint:fix": "biome lint --write .",
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 功能:静态检查三套管理后台的账户角色中文展示与无效头像摘要规则。
|
||||
* 版本:v1.0.0
|
||||
*/
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const appRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const frontendRoot = resolve(appRoot, '..');
|
||||
|
||||
function source(path) {
|
||||
return readFileSync(resolve(frontendRoot, path), 'utf8');
|
||||
}
|
||||
|
||||
function expectIncludes(content, marker, message) {
|
||||
if (!content.includes(marker)) throw new Error(`账户角色检查失败:${message}`);
|
||||
}
|
||||
|
||||
const platformResources = source('platform_admin/src/api/resources.ts');
|
||||
const platformPage = source(
|
||||
'platform_admin/src/views/resource/ResourceRecordPage.vue',
|
||||
);
|
||||
const platformSummary = source(
|
||||
'platform_admin/src/views/resource/ResourceAccountSummary.vue',
|
||||
);
|
||||
|
||||
expectIncludes(
|
||||
platformResources,
|
||||
"fixedAdminRole('气站管理员')",
|
||||
'平台总后台缺少气站管理员中文映射',
|
||||
);
|
||||
expectIncludes(
|
||||
platformResources,
|
||||
"fixedAdminRole('配送点管理员')",
|
||||
'平台总后台缺少配送点管理员中文映射',
|
||||
);
|
||||
expectIncludes(
|
||||
platformResources,
|
||||
"define('delivery_account', '配送点账户'",
|
||||
'配送点账户名称未统一',
|
||||
);
|
||||
expectIncludes(
|
||||
platformPage,
|
||||
"mode.value !== 'create' || hasAvatarField.value",
|
||||
'无头像能力的新建账户页仍可能显示无效占位摘要',
|
||||
);
|
||||
expectIncludes(
|
||||
platformSummary,
|
||||
'v-if="avatarEnabled" class="avatar-column"',
|
||||
'无头像能力的账户仍可能显示装饰头像',
|
||||
);
|
||||
|
||||
for (const app of ['gas_admin', 'delivery_admin']) {
|
||||
const resources = source(`${app}/src/api/resources.ts`);
|
||||
const listPage = source(`${app}/src/views/shared/CrudListPage.vue`);
|
||||
expectIncludes(
|
||||
resources,
|
||||
"fixedAdminRole('配送点管理员')",
|
||||
`${app} 缺少配送点管理员中文映射`,
|
||||
);
|
||||
expectIncludes(
|
||||
listPage,
|
||||
"'/gas_account': { admin: '气站管理员' }",
|
||||
`${app} 缺少气站管理员显示规则`,
|
||||
);
|
||||
expectIncludes(
|
||||
listPage,
|
||||
"'/delivery_account': { admin: '配送点管理员' }",
|
||||
`${app} 缺少配送点管理员显示规则`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log('账户角色检查通过:三套后台中文角色、未知角色和头像摘要规则均已覆盖。');
|
||||
@@ -33,7 +33,7 @@ export type PlatformMenu = { identity: string; parent_identity?: string; group_c
|
||||
export const platformApi = {
|
||||
overview: () => request<DashboardOverview>('/dashboard/overview'),
|
||||
listAccount: () => request<{ total: number; list: Record<string, unknown>[] }>('/platform_account'),
|
||||
listRole: () => resourceApi.list<PlatformRole>('/platform_role'),
|
||||
listRole: () => resourceApi.list<PlatformRole>('/platform_role', 1, 100),
|
||||
createRole: (data: Record<string, unknown>) => resourceApi.create<PlatformRole>('/platform_role', data),
|
||||
listMenu: () => request<{ total: number; list: PlatformMenu[] }>('/platform_menu'),
|
||||
listRoleMenuIdentities: (identity: string) =>
|
||||
|
||||
@@ -161,13 +161,21 @@ export function displayResourceField(
|
||||
field: ResourceField,
|
||||
row: ResourceRow,
|
||||
relationOptions: Record<string, ResourceRow[]>,
|
||||
fieldOptions: Record<string, Array<{ label: string; value: string | number }>> = {},
|
||||
) {
|
||||
const value = row[field.key] ?? row[`${field.key}_masked`];
|
||||
if (value == null || value === '') return field.emptyText ?? '-';
|
||||
const option = field.options?.find(
|
||||
const hasOptionSource =
|
||||
Object.prototype.hasOwnProperty.call(fieldOptions, field.key) ||
|
||||
Boolean(field.options);
|
||||
const options = fieldOptions[field.key] ?? field.options;
|
||||
const option = options?.find(
|
||||
(item) => String(item.value) === String(value),
|
||||
);
|
||||
if (option) return option.label;
|
||||
if (hasOptionSource && field.unknownValueLabel) {
|
||||
return `${field.unknownValueLabel}(${String(value)})`;
|
||||
}
|
||||
if (field.type === 'identity' && typeof value === 'string') {
|
||||
return relationLabel(field, value, relationOptions);
|
||||
}
|
||||
|
||||
@@ -33,14 +33,13 @@ const pageRules: Record<string, ResourcePageRule> = {
|
||||
],
|
||||
},
|
||||
gas_account: {
|
||||
editKeys: ['display_name', 'role_code', 'gas_basic_identity'],
|
||||
editKeys: ['display_name', 'gas_basic_identity'],
|
||||
accountSummary: true,
|
||||
},
|
||||
delivery_basic: {
|
||||
editKeys: ['name', 'gas_basic_identity', 'principal', 'address'],
|
||||
},
|
||||
delivery_account: {
|
||||
createHiddenKeys: ['role_code'],
|
||||
editKeys: ['display_name', 'delivery_basic_identity'],
|
||||
accountSummary: true,
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ export function resetResourceRecordForm(
|
||||
const value = row[field.key];
|
||||
form[field.key] =
|
||||
value == null
|
||||
? undefined
|
||||
? field.defaultValue
|
||||
: field.type === 'money'
|
||||
? Number(value) / 100
|
||||
: value;
|
||||
|
||||
@@ -29,6 +29,9 @@ export type ResourceField = {
|
||||
emptyText?: string;
|
||||
placeholder?: string;
|
||||
options?: Array<{ label: string; value: string | number }>;
|
||||
defaultValue?: string | number | boolean;
|
||||
readonlyOnCreate?: boolean;
|
||||
unknownValueLabel?: string;
|
||||
};
|
||||
|
||||
export type DetailAction = {
|
||||
@@ -68,7 +71,7 @@ const fieldLabels: Record<string, string> = {
|
||||
username: '用户名',
|
||||
password: '密码',
|
||||
display_name: '显示名称',
|
||||
role_code: '角色编码',
|
||||
role_code: '角色',
|
||||
platform_role_code: '平台角色',
|
||||
credit_code: '统一社会信用代码',
|
||||
principal: '负责人',
|
||||
@@ -281,6 +284,20 @@ function relation(key: string, resource: string, required = false): ResourceFiel
|
||||
return f(key, { type: 'identity', relation: resource, required });
|
||||
}
|
||||
|
||||
/** 创建固定管理员角色字段,页面展示中文名称,接口仍使用稳定编码。 */
|
||||
function fixedAdminRole(label: string): ResourceField {
|
||||
return f('role_code', {
|
||||
label: '角色',
|
||||
listLabel: '角色',
|
||||
type: 'select',
|
||||
required: true,
|
||||
options: [{ label, value: 'admin' }],
|
||||
defaultValue: 'admin',
|
||||
readonlyOnCreate: true,
|
||||
unknownValueLabel: '未知角色',
|
||||
});
|
||||
}
|
||||
|
||||
function define(
|
||||
name: string,
|
||||
title: string,
|
||||
@@ -319,9 +336,9 @@ const reason = [f('reason', { required: true })];
|
||||
|
||||
export const resources: ResourceUiDefinition[] = [
|
||||
{ ...define('gas_basic', '气站管理', 'writable', [f('code', { required: true }), f('name', { required: true }), f('credit_code'), f('principal'), f('address'), f('longitude'), f('latitude')]), accountManagement: { resource: '/gas_account', relationKey: 'gas_basic_identity', title: '气站账户' }, walletOwnerType: 'gas' },
|
||||
define('gas_account', '气站账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), f('role_code'), relation('gas_basic_identity', '/gas_basic', true)]),
|
||||
define('gas_account', '气站账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), fixedAdminRole('气站管理员'), relation('gas_basic_identity', '/gas_basic', true)]),
|
||||
{ ...define('delivery_basic', '配送点管理', 'writable', [f('delivery_code', { required: true }), f('name', { required: true }), f('gas_basic_identity', { label: '气站', listLabel: '气站名称', type: 'identity', relation: '/gas_basic', displayRelationLabel: true, emptyText: '平台直属', placeholder: '请选择气站,留空表示平台直属' }), f('principal'), f('address')]), accountManagement: { resource: '/delivery_account', relationKey: 'delivery_basic_identity', title: '配送点账户' }, walletOwnerType: 'delivery' },
|
||||
define('delivery_account', '配送站账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), f('role_code'), relation('delivery_basic_identity', '/delivery_basic', true)]),
|
||||
define('delivery_account', '配送点账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), fixedAdminRole('配送点管理员'), relation('delivery_basic_identity', '/delivery_basic', true)]),
|
||||
{ ...define('staff_account', '工作人员', 'writable', [f('username', { required: true }), f('password', { required: true }), f('name', { required: true }), f('phone'), f('avatar'), f('role_code', { required: true, type: 'select', options: [{ label: '安装人员', value: 'installer' }, { label: '配送人员', value: 'delivery' }, { label: '运维人员', value: 'operations' }] }), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), f('work_status', { type: 'select', options: [{ label: '在岗', value: 'on_duty' }, { label: '离岗', value: 'off_duty' }] })]), walletOwnerType: 'staff' },
|
||||
define('staff_credential', '工作人员资质', 'writable', [relation('staff_account_identity', '/staff_account', true), f('credential_type', { required: true }), f('credential_no'), f('expired_at')]),
|
||||
{ ...define('user_account', '用户账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('name', { required: true }), f('phone'), f('avatar'), f('real_name')]), walletOwnerType: 'user' },
|
||||
@@ -418,7 +435,7 @@ export const resources: ResourceUiDefinition[] = [
|
||||
define('fin_reconciliation', '财务对账', 'readonly', []),
|
||||
define('cms_content', '内容', 'writable', [f('content_type', { required: true }), f('title', { required: true }), f('body', { required: true }), f('version_no'), f('publish_status')]),
|
||||
define('cs_ticket', '客服工单', 'writable', [relation('user_account_identity', '/user_account', true), f('ticket_no', { required: true }), f('category', { required: true }), f('priority', { required: true })]),
|
||||
define('platform_account', '平台账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), f('avatar'), f('platform_role_code', { required: true }), f('phone')]),
|
||||
define('platform_account', '平台账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), f('avatar'), f('platform_role_code', { required: true, unknownValueLabel: '未知角色' }), f('phone')]),
|
||||
define('platform_role', '平台角色', 'writable', [f('role_code', { required: true }), f('name', { required: true }), f('location_scope', { required: true, type: 'select', options: [{ label: '脱敏坐标', value: 'standard' }, { label: '精确坐标', value: 'precise' }] })], 'list', [
|
||||
{ name: '分配菜单', resource: '/platform_role/:identity/menu', method: 'PUT', fields: [f('menu_identities', { type: 'identity-list', relation: '/platform_menu' })] },
|
||||
]),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!--
|
||||
功能:展示账户类资源的头像、用户名、唯一标识和创建时间摘要。
|
||||
版本:v1.0.0
|
||||
版本:v1.1.0
|
||||
-->
|
||||
<template>
|
||||
<a-card class="account-card" :bordered="false">
|
||||
<div class="account-summary">
|
||||
<div class="avatar-column">
|
||||
<div class="account-summary" :class="{ 'account-summary-text': !avatarEnabled }">
|
||||
<div v-if="avatarEnabled" class="avatar-column">
|
||||
<button
|
||||
class="avatar-button"
|
||||
type="button"
|
||||
@@ -106,6 +106,15 @@ function onAvatarSelected(event: Event) {
|
||||
min-height: 168px;
|
||||
padding: 18px 32px;
|
||||
}
|
||||
.account-summary-text {
|
||||
grid-template-columns: minmax(420px, 720px);
|
||||
justify-content: start;
|
||||
min-height: 116px;
|
||||
padding: 14px 32px;
|
||||
}
|
||||
.account-summary-text .identity-summary {
|
||||
width: 100%;
|
||||
}
|
||||
.avatar-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -188,5 +197,10 @@ function onAvatarSelected(event: Event) {
|
||||
width: min(100%, 440px);
|
||||
margin: 0 auto;
|
||||
}
|
||||
.account-summary-text {
|
||||
grid-template-columns: 1fr;
|
||||
min-height: auto;
|
||||
padding: 14px 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
功能:以响应式信息卡和子表页签展示标准资源详情。
|
||||
版本:v1.1.0
|
||||
版本:v1.2.0
|
||||
-->
|
||||
<template>
|
||||
<div class="detail-stack">
|
||||
@@ -58,6 +58,10 @@ const props = defineProps<{
|
||||
definition: ResourceUiDefinition;
|
||||
detail: ResourceRow;
|
||||
relationOptions: Record<string, ResourceRow[]>;
|
||||
fieldOptions?: Record<
|
||||
string,
|
||||
Array<{ label: string; value: string | number }>
|
||||
>;
|
||||
accountSummary: boolean;
|
||||
}>();
|
||||
|
||||
@@ -97,7 +101,12 @@ const entries = computed<DetailEntry[]>(() => {
|
||||
return [];
|
||||
const field = props.definition.fields.find((item) => item.key === key);
|
||||
const display = field
|
||||
? displayResourceField(field, row, props.relationOptions)
|
||||
? displayResourceField(
|
||||
field,
|
||||
row,
|
||||
props.relationOptions,
|
||||
props.fieldOptions,
|
||||
)
|
||||
: displayRawValue(actualKey, value);
|
||||
const objectValue = typeof value === 'object' && value !== null;
|
||||
return [
|
||||
@@ -161,7 +170,8 @@ const collections = computed(() =>
|
||||
}
|
||||
.detail-item {
|
||||
display: grid;
|
||||
grid-template-columns: 120px minmax(0, 1fr);
|
||||
grid-template-columns: max-content minmax(0, 1fr);
|
||||
column-gap: 12px;
|
||||
align-items: start;
|
||||
min-height: 38px;
|
||||
padding: 8px 0;
|
||||
@@ -172,8 +182,7 @@ const collections = computed(() =>
|
||||
}
|
||||
.detail-label {
|
||||
color: var(--color-text-3);
|
||||
text-align: right;
|
||||
padding-right: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.detail-value {
|
||||
color: var(--color-text-1);
|
||||
@@ -208,7 +217,6 @@ const collections = computed(() =>
|
||||
.detail-item,
|
||||
.detail-item-wide {
|
||||
grid-column: auto;
|
||||
grid-template-columns: 100px minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
功能:渲染标准资源的新建、编辑和业务动作字段控件。
|
||||
版本:v1.0.0
|
||||
版本:v1.1.0
|
||||
-->
|
||||
<template>
|
||||
<div class="field-grid">
|
||||
@@ -63,7 +63,7 @@
|
||||
:disabled="disabledSet.has(field.key)"
|
||||
allow-clear
|
||||
>
|
||||
<a-option v-for="option in field.options" :key="option.value" :value="option.value">
|
||||
<a-option v-for="option in selectOptions(field)" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
@@ -90,9 +90,8 @@
|
||||
v-else
|
||||
v-model="model[field.key]"
|
||||
:disabled="disabledSet.has(field.key)"
|
||||
:placeholder="disabledSet.has(field.key) ? '创建后不可修改' : `请输入${field.label}`"
|
||||
:placeholder="disabledSet.has(field.key) ? '' : `请输入${field.label}`"
|
||||
/>
|
||||
<div v-if="disabledSet.has(field.key)" class="readonly-hint">创建后不可修改</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
@@ -135,6 +134,24 @@ function isWide(field: ResourceField) {
|
||||
/(address|terms|content|body|remark|reason|params|args)$/.test(field.key)
|
||||
);
|
||||
}
|
||||
|
||||
/** 为历史未知编码补充只读选项,避免下拉框退回显示原始值。 */
|
||||
function selectOptions(field: ResourceField) {
|
||||
const options = [...(field.options ?? [])];
|
||||
const value = model.value[field.key];
|
||||
if (
|
||||
field.unknownValueLabel &&
|
||||
value != null &&
|
||||
value !== '' &&
|
||||
!options.some((option) => String(option.value) === String(value))
|
||||
) {
|
||||
options.push({
|
||||
label: `${field.unknownValueLabel}(${String(value)})`,
|
||||
value,
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -152,11 +169,6 @@ function isWide(field: ResourceField) {
|
||||
.field-readonly :deep(.arco-input-number) {
|
||||
background: var(--color-fill-1);
|
||||
}
|
||||
.readonly-hint {
|
||||
margin-top: 4px;
|
||||
color: var(--color-text-3);
|
||||
font-size: 12px;
|
||||
}
|
||||
:deep(.arco-input-number),
|
||||
:deep(.arco-picker) {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 功能:定义标准资源独立页面的布局、卡片和响应式样式。
|
||||
* 版本:v1.2.0
|
||||
* 版本:v1.3.0
|
||||
*/
|
||||
.record-page {
|
||||
display: grid;
|
||||
@@ -52,7 +52,6 @@
|
||||
.form-content {
|
||||
container: record-form / inline-size;
|
||||
}
|
||||
.form-alert,
|
||||
.workflow-alert {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
功能:承载平台总后台全部标准资源的新建、详情和编辑独立页面。
|
||||
版本:v1.2.0
|
||||
版本:v1.3.0
|
||||
-->
|
||||
<template>
|
||||
<div class="record-page">
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<template v-else>
|
||||
<ResourceAccountSummary
|
||||
v-if="accountSummary"
|
||||
v-if="accountSummaryVisible"
|
||||
:mode="mode"
|
||||
:title="definition.title"
|
||||
:record="summaryRecord"
|
||||
@@ -49,6 +49,7 @@
|
||||
:definition="definition"
|
||||
:detail="detail"
|
||||
:relation-options="relations.options"
|
||||
:field-options="fieldOptions"
|
||||
:account-summary="accountSummary"
|
||||
/>
|
||||
<ResourceWalletSummary
|
||||
@@ -93,9 +94,6 @@
|
||||
<div class="form-shell">基本信息</div>
|
||||
</template>
|
||||
<div class="form-shell form-content">
|
||||
<a-alert v-if="mode === 'edit' && readonlyKeys.length" class="form-alert" type="info" show-icon>
|
||||
灰色字段为创建后不可修改的信息,不会提交到更新接口。
|
||||
</a-alert>
|
||||
<a-form :model="form" layout="vertical">
|
||||
<ResourceFieldForm
|
||||
v-model="form"
|
||||
@@ -196,6 +194,9 @@ const errorMessage = ref('');
|
||||
const errorStatus = ref<'403' | '404' | 'error'>('error');
|
||||
const wallet = ref<ResourceRow>();
|
||||
const roleOptions = ref<PlatformRole[]>([]);
|
||||
const fieldOptions = reactive<
|
||||
Record<string, Array<{ label: string; value: string | number }>>
|
||||
>({});
|
||||
const relations = useResourceRelations();
|
||||
const actionVisible = ref(false);
|
||||
const activeAction = ref<DetailAction>();
|
||||
@@ -206,6 +207,11 @@ const selectAvatar = avatar.select;
|
||||
const clearAvatar = avatar.clear;
|
||||
|
||||
const accountSummary = computed(() => usesAccountSummary(definition.value));
|
||||
const accountSummaryVisible = computed(
|
||||
() =>
|
||||
accountSummary.value &&
|
||||
(mode.value !== 'create' || hasAvatarField.value),
|
||||
);
|
||||
const hasAvatarField = computed(() =>
|
||||
definition.value.fields.some((field) => field.key === 'avatar'),
|
||||
);
|
||||
@@ -235,11 +241,15 @@ const editableKeySet = computed(
|
||||
),
|
||||
);
|
||||
const readonlyKeys = computed(() =>
|
||||
mode.value === 'edit'
|
||||
mode.value === 'create'
|
||||
? formFields.value
|
||||
.filter((field) => field.readonlyOnCreate)
|
||||
.map((field) => field.key)
|
||||
: mode.value === 'edit'
|
||||
? formFields.value
|
||||
.filter((field) => !editableKeySet.value.has(field.key))
|
||||
.map((field) => field.key)
|
||||
: [],
|
||||
: [],
|
||||
);
|
||||
const requiredKeys = computed(() =>
|
||||
payloadFields.value
|
||||
@@ -353,9 +363,19 @@ async function loadRelationsAndRoles() {
|
||||
if (
|
||||
definition.value.fields.some((field) => field.key === 'platform_role_code')
|
||||
) {
|
||||
roleOptions.value = (await platformApi.listRole()).list.filter(
|
||||
(role) => !role.is_system && role.status === 1,
|
||||
);
|
||||
try {
|
||||
const roles = (await platformApi.listRole()).list;
|
||||
fieldOptions.platform_role_code = roles.map((role) => ({
|
||||
label: role.name,
|
||||
value: role.role_code,
|
||||
}));
|
||||
roleOptions.value = roles.filter(
|
||||
(role) => !role.is_system && role.status === 1,
|
||||
);
|
||||
} catch (error) {
|
||||
fieldOptions.platform_role_code = [];
|
||||
Message.warning(`平台角色加载失败:${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
v-if="field.type === 'identity' && !field.displayRelationLabel && identityFieldValue(field, record)"
|
||||
:value="identityFieldValue(field, record)"
|
||||
/>
|
||||
<template v-else>{{ displayResourceField(field, record, relations.options) }}</template>
|
||||
<template v-else>{{ displayListField(field, record) }}</template>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column v-if="definition.accountManagement" title="账户数" :width="90">
|
||||
@@ -148,6 +148,7 @@ import {
|
||||
import { editBlockedReason, type ResourceRow } from '@/api/resource-page-rules';
|
||||
import { safeReturnPath } from '@/api/resource-navigation';
|
||||
import { resourceApi } from '@/api/resource';
|
||||
import { platformApi } from '@/api/platform';
|
||||
import type { ResourceField, ResourceUiDefinition } from '@/api/resources';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useResourceRelations } from '../resource/use-resource-relations';
|
||||
@@ -167,6 +168,9 @@ const filters = reactive({
|
||||
keyword: typeof route.query.keyword === 'string' ? route.query.keyword : '',
|
||||
});
|
||||
const relations = useResourceRelations();
|
||||
const fieldOptions = reactive<
|
||||
Record<string, Array<{ label: string; value: string | number }>>
|
||||
>({});
|
||||
const extras = useResourceListExtras(definitionRef, list);
|
||||
const statusVisible = ref(false);
|
||||
const statusSaving = ref(false);
|
||||
@@ -426,8 +430,38 @@ function columnWidth(field: ResourceField) {
|
||||
return 180;
|
||||
}
|
||||
|
||||
/** 使用资源静态选项或运行时平台角色名称显示列表字段。 */
|
||||
function displayListField(field: ResourceField, row: ResourceRow) {
|
||||
return displayResourceField(field, row, relations.options, fieldOptions);
|
||||
}
|
||||
|
||||
/** 平台角色由后端维护,列表加载全部角色用于编码转中文名称。 */
|
||||
async function loadFieldOptions() {
|
||||
if (
|
||||
!props.definition.fields.some(
|
||||
(field) => field.key === 'platform_role_code',
|
||||
)
|
||||
) {
|
||||
delete fieldOptions.platform_role_code;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const roles = (await platformApi.listRole()).list;
|
||||
fieldOptions.platform_role_code = roles.map((role) => ({
|
||||
label: role.name,
|
||||
value: role.role_code,
|
||||
}));
|
||||
} catch (error) {
|
||||
fieldOptions.platform_role_code = [];
|
||||
Message.warning(`平台角色加载失败:${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await relations.preload(displayFields.value);
|
||||
await Promise.all([
|
||||
relations.preload(displayFields.value),
|
||||
loadFieldOptions(),
|
||||
]);
|
||||
await load();
|
||||
});
|
||||
watch(
|
||||
@@ -435,7 +469,10 @@ watch(
|
||||
async () => {
|
||||
page.value = 1;
|
||||
filters.keyword = '';
|
||||
await relations.preload(displayFields.value);
|
||||
await Promise.all([
|
||||
relations.preload(displayFields.value),
|
||||
loadFieldOptions(),
|
||||
]);
|
||||
await load();
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user