task-263(admin.html观感对齐): 店铺管理页对齐(密码眼睛实时读取/修改时间列/整句必填校验/编辑密码必填语义/删除文案)

This commit is contained in:
2026-09-05 22:04:20 +08:00
parent a7cdb0031a
commit 5e4a2a9d11
2 changed files with 115 additions and 4 deletions
@@ -33,8 +33,35 @@ const form = reactive(emptyShopManageForm())
const credentialVisible = ref(false)
const credential = ref<ShopCredential | null>(null)
/** 密码列“眼睛”实时读取:仅展示已读明文,其余保持掩码;读取中占位。 */
const revealedPasswordCache = ref<Record<number, string>>({})
const revealedRowId = ref<number | null>(null)
const groupOptions = computed(() => groups.value)
function shownPassword(row: ShopSummary): string {
if (revealedRowId.value !== row.id) return row.passwordMasked || '******'
const plain = revealedPasswordCache.value[row.id]
return plain != null && plain !== '' ? plain : '读取中...'
}
async function togglePassword(row: ShopSummary) {
if (revealedRowId.value === row.id) {
revealedRowId.value = null
return
}
revealedRowId.value = row.id
if (revealedPasswordCache.value[row.id] == null) {
try {
const cred = await fetchShopCredential(row.id, row.shopName)
revealedPasswordCache.value[row.id] = cred.password
} catch (error) {
revealedRowId.value = null
ElMessage.error(error instanceof Error ? error.message : '读取密码失败')
}
}
}
async function loadGroups() {
try {
groups.value = await fetchShopManageGroups()
@@ -94,6 +121,16 @@ function openEdit(row: ShopSummary) {
}
async function submit() {
if (
form.groupId == null ||
!(form.shopName || '').trim() ||
!(form.mallName || '').trim() ||
!(form.account || '').trim() ||
!(form.password || '').trim()
) {
ElMessage.warning('请完整填写分组、店铺名、店铺商城名、账号、密码')
return
}
saving.value = true
try {
const createdById = session.user?.id ?? 0
@@ -124,7 +161,7 @@ async function showCredential(row: ShopSummary) {
async function remove(row: ShopSummary) {
try {
await ElMessageBox.confirm(`删除店铺${row.shopName}`, '删除店铺', { type: 'warning' })
await ElMessageBox.confirm(`删除店铺${row.shopName}”吗`, '删除确认', { type: 'warning' })
} catch {
return
}
@@ -188,8 +225,19 @@ onMounted(() => {
<el-table-column prop="mallName" label="商城" min-width="120" />
<el-table-column prop="groupName" label="分组" min-width="120" />
<el-table-column prop="account" label="账号" min-width="140" />
<el-table-column label="密码" width="140">
<template #default="{ row }">{{ (row as ShopSummary).passwordMasked || '—' }}</template>
<el-table-column label="密码" width="170">
<template #default="{ row }">
<span class="pwd-cell">{{ shownPassword(row as ShopSummary) }}</span>
<el-button
link
type="primary"
size="small"
:aria-label="revealedRowId === (row as ShopSummary).id ? '隐藏密码' : '显示密码'"
@click="togglePassword(row as ShopSummary)"
>
{{ revealedRowId === (row as ShopSummary).id ? '隐藏' : '显示' }}
</el-button>
</template>
</el-table-column>
<el-table-column prop="znUsername" label="自动化账号" min-width="140">
<template #default="{ row }">{{ (row as ShopSummary).znUsername || '—' }}</template>
@@ -197,6 +245,9 @@ onMounted(() => {
<el-table-column prop="createdAt" label="创建时间" min-width="170">
<template #default="{ row }">{{ formatDateTime(row.createdAt) }}</template>
</el-table-column>
<el-table-column prop="updatedAt" label="修改时间" min-width="170">
<template #default="{ row }">{{ formatDateTime(row.updatedAt) }}</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template #default="{ row }">
<el-button text type="primary" size="small" @click="openEdit(row as ShopSummary)">编辑</el-button>
@@ -228,7 +279,7 @@ onMounted(() => {
<el-input v-model="form.account" placeholder="登录账号" />
</el-form-item>
<el-form-item label="密码" required>
<el-input v-model="form.password" type="password" show-password :placeholder="editingId == null ? '登录密码' : '留空则不修改?(后端必填,编辑需重填)'" />
<el-input v-model="form.password" type="password" show-password :placeholder="editingId == null ? '登录密码' : '后端必填,编辑请重新填写登录密码'" />
</el-form-item>
<el-form-item label="自动化账号">
<el-input v-model="form.znUsername" placeholder="可选紫鸟自动化账号" />
@@ -267,4 +318,5 @@ onMounted(() => {
.table-footer span { color: var(--el-text-color-secondary); font-size: 12.5px; }
.table-footer b { color: var(--el-text-color-primary); }
.dim { color: var(--el-text-color-secondary); font-size: 12px; }
.pwd-cell { font-family: Consolas, monospace; font-size: 12px; margin-right: 6px; }
</style>