修复配送端合同与用户管理问题
This commit is contained in:
@@ -74,6 +74,9 @@ const listPage = read('src/views/shared/ResourceListPage.vue');
|
||||
assert(!listPage.includes('title="ID"'), '标准列表仍暴露数据库自增 ID');
|
||||
assert(listPage.includes('ProtectedAvatarThumbnail'), '账户列表尚未接入受控头像缩略图');
|
||||
assert(listPage.includes('avatarLoader.reset()'), '列表刷新未清理头像缓存和请求');
|
||||
assert(listPage.includes('field.listRelationNameOnly && fieldValue(field, record)'), '关系列表字段尚未按气站端显示业务名称');
|
||||
assert(listPage.includes('relationListName(field, record)'), '关系列表字段缺少服务端派生名称读取');
|
||||
assert(listPage.includes('@open="openRelation(field, record)"'), '关系列表名称缺少关联详情入口');
|
||||
const avatarLoader = read('src/views/shared/protected-list-avatar-loader.ts');
|
||||
assert(avatarLoader.includes('MAX_CONCURRENT_REQUESTS = 6'), '头像请求并发上限未与 5173 对齐');
|
||||
assert(avatarLoader.includes("new Set(['staff_account', 'user_account'])"), '头像列表资源白名单不正确');
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<!-- 功能描述:以业务名称展示关联记录,并保留唯一标识的查看与复制能力。版本:v1.0.0。 -->
|
||||
<!-- 功能描述:以关系名称为主展示,支持进入关联详情并复制完整唯一标识。版本:v1.1.0。 -->
|
||||
<template>
|
||||
<div class="relation-name-text">
|
||||
<a-tooltip :content="`${identityLabel}:${identity}`">
|
||||
<span class="relation-name">{{ displayName }}</span>
|
||||
<button
|
||||
v-if="clickable"
|
||||
class="relation-name relation-link"
|
||||
type="button"
|
||||
@click.stop="emit('open')"
|
||||
>{{ displayName }}</button>
|
||||
<span v-else class="relation-name">{{ displayName }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip :content="`复制${identityLabel}`">
|
||||
<button class="copy-button" type="button" :aria-label="`复制${identityLabel} ${identity}`" @click.stop="copyIdentity">
|
||||
@@ -17,14 +23,20 @@ import { Message } from '@arco-design/web-vue';
|
||||
import { IconCopy } from '@arco-design/web-vue/es/icon';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps<{ name: string; identity: string; identityLabel: string }>();
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
identity: string;
|
||||
identityLabel?: string;
|
||||
clickable?: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{ open: [] }>();
|
||||
const displayName = computed(() => props.name || props.identity);
|
||||
|
||||
/** 复制完整唯一标识,并给出明确的操作反馈。 */
|
||||
async function copyIdentity() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(props.identity);
|
||||
Message.success(`${props.identityLabel}已复制`);
|
||||
Message.success(`${props.identityLabel ?? '唯一标识'}已复制`);
|
||||
} catch {
|
||||
Message.error('复制失败,请从悬浮提示中复制');
|
||||
}
|
||||
@@ -34,6 +46,7 @@ async function copyIdentity() {
|
||||
<style scoped>
|
||||
.relation-name-text { display: flex; gap: 6px; align-items: center; min-width: 0; }
|
||||
.relation-name { min-width: 0; overflow: hidden; color: var(--color-text-1); text-overflow: ellipsis; white-space: nowrap; }
|
||||
.relation-link { padding: 0; color: rgb(var(--primary-6)); font: inherit; text-align: left; background: transparent; border: 0; cursor: pointer; }
|
||||
.copy-button { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; color: rgb(var(--primary-6)); font-size: 14px; background: transparent; border: 0; border-radius: 4px; cursor: pointer; }
|
||||
.copy-button:hover, .copy-button:focus-visible { background: var(--color-fill-2); outline: none; }
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 功能描述:展示配送点标准资源列表并导航到独立记录页。版本:v1.2.0。 -->
|
||||
<!-- 功能描述:展示配送点标准资源列表并导航到独立记录页。版本:v1.3.0。 -->
|
||||
<template>
|
||||
<a-card :title="listTitle" :bordered="false">
|
||||
<template v-if="isCredentialList" #extra>
|
||||
@@ -56,8 +56,8 @@
|
||||
:title="field.listLabel ?? field.label"
|
||||
:width="columnWidth(field)"
|
||||
:align="isProtectedListAvatarField(definition.name, field.key) ? 'center' : 'left'"
|
||||
:ellipsis="!isProtectedListAvatarField(definition.name, field.key)"
|
||||
:tooltip="!isProtectedListAvatarField(definition.name, field.key)"
|
||||
:ellipsis="!isProtectedListAvatarField(definition.name, field.key) && !field.listRelationNameOnly"
|
||||
:tooltip="!isProtectedListAvatarField(definition.name, field.key) && !field.listRelationNameOnly"
|
||||
>
|
||||
<template #cell="{ record }">
|
||||
<ProtectedAvatarThumbnail
|
||||
@@ -68,6 +68,14 @@
|
||||
:refresh-key="avatarRefreshKey"
|
||||
:loader="avatarLoader"
|
||||
/>
|
||||
<RelationNameText
|
||||
v-else-if="field.listRelationNameOnly && fieldValue(field, record)"
|
||||
:name="relationListName(field, record)"
|
||||
:identity="fieldValue(field, record)"
|
||||
:identity-label="field.listLabel ?? field.label"
|
||||
:clickable="Boolean(field.relation)"
|
||||
@open="openRelation(field, record)"
|
||||
/>
|
||||
<a-button
|
||||
v-else-if="field.type === 'contract-file' && record.has_attachment"
|
||||
size="mini"
|
||||
@@ -147,6 +155,7 @@ import type { ResourceRow } from '@/api/resource-record-form';
|
||||
import { resourceFieldLabel, type ResourceField, type ResourceUiDefinition } from '@/api/resources';
|
||||
import IdentityText from '@/components/IdentityText.vue';
|
||||
import ProtectedAvatarThumbnail from './ProtectedAvatarThumbnail.vue';
|
||||
import RelationNameText from './RelationNameText.vue';
|
||||
import {
|
||||
createProtectedListAvatarLoader,
|
||||
isProtectedListAvatarField,
|
||||
@@ -216,6 +225,7 @@ async function ensureCredentialContext() {
|
||||
/** 返回列表列宽。 */
|
||||
function columnWidth(field: ResourceField) {
|
||||
if (isProtectedListAvatarField(props.definition.name, field.key)) return 72;
|
||||
if (field.listRelationNameOnly) return 240;
|
||||
if (field.type === 'contract-file') return 120;
|
||||
if (field.type === 'datetime' || field.type === 'date') return 180;
|
||||
if (field.type === 'money') return 160;
|
||||
@@ -249,6 +259,28 @@ function fieldValue(field: ResourceField, row: ResourceRow) {
|
||||
return String(row[field.key] ?? row[`${field.key}_masked`] ?? '');
|
||||
}
|
||||
|
||||
/** 优先读取服务端在当前合同范围内返回的关联业务名称。 */
|
||||
function relationListName(field: ResourceField, row: ResourceRow) {
|
||||
const displayKey = field.key.endsWith('_identity')
|
||||
? `${field.key.slice(0, -9)}_display_name`
|
||||
: '';
|
||||
return displayKey ? String(row[displayKey] ?? '').trim() : '';
|
||||
}
|
||||
|
||||
/** 打开关系字段对应的独立详情页。 */
|
||||
function openRelation(field: ResourceField, row: ResourceRow) {
|
||||
if (!field.relation) return;
|
||||
const target = router.getRoutes().find(
|
||||
(item) => item.meta.resource === field.relation && item.meta.recordMode === 'detail',
|
||||
);
|
||||
if (!target?.name) return;
|
||||
return router.push({
|
||||
name: target.name,
|
||||
params: { identity: fieldValue(field, row) },
|
||||
query: { return_to: route.fullPath },
|
||||
});
|
||||
}
|
||||
|
||||
/** 优先使用后端受控派生字段展示列表摘要,空值使用字段业务文案。 */
|
||||
function displayListField(field: ResourceField, row: ResourceRow) {
|
||||
if (field.listDisplayKey) {
|
||||
|
||||
Reference in New Issue
Block a user