增加前端格式检查配置
This commit is contained in:
@@ -60,8 +60,12 @@ function nextPage() {
|
||||
<el-option :value="100" label="100条" />
|
||||
</el-select>
|
||||
<span class="pagination-page">{{ currentPage }}/{{ totalPages }}页</span>
|
||||
<el-button size="small" :disabled="currentPage <= 1 || loading" @click="prevPage">上页</el-button>
|
||||
<el-button size="small" :disabled="currentPage >= totalPages || loading" @click="nextPage">下页</el-button>
|
||||
<el-button size="small" :disabled="currentPage <= 1 || loading" @click="prevPage"
|
||||
>上页</el-button
|
||||
>
|
||||
<el-button size="small" :disabled="currentPage >= totalPages || loading" @click="nextPage"
|
||||
>下页</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { createAdminMgrUser, updateAdminMgrUser, type AdminMgrUser, type CreateAdminRequest, type UpdateAdminRequest } from '@/features/admin/api/adminMgr'
|
||||
import {
|
||||
createAdminMgrUser,
|
||||
updateAdminMgrUser,
|
||||
type AdminMgrUser,
|
||||
type CreateAdminRequest,
|
||||
type UpdateAdminRequest,
|
||||
} from '@/features/admin/api/adminMgr'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
@@ -26,7 +32,7 @@ const isEdit = ref(false)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
if (props.admin) {
|
||||
isEdit.value = true
|
||||
@@ -42,7 +48,7 @@ watch(
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
async function handleSave() {
|
||||
@@ -94,7 +100,12 @@ function readError(error: unknown, fallback: string) {
|
||||
<el-input v-model="form.username" :disabled="isEdit" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isEdit" label="密码" class="full-control">
|
||||
<el-input v-model="form.password" type="password" show-password placeholder="请输入密码(至少6位)" />
|
||||
<el-input
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入密码(至少6位)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" class="full-control">
|
||||
<el-input v-model="form.nickname" placeholder="请输入昵称" />
|
||||
|
||||
@@ -3,7 +3,10 @@ import { computed, ref, watch } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { Bell, Document, QuestionFilled, Warning } from '@element-plus/icons-vue'
|
||||
import type { Announcement } from '@/features/announcement'
|
||||
import type { CreateAnnouncementRequest, UpdateAnnouncementRequest } from '@/features/admin/api/adminAnnouncements'
|
||||
import type {
|
||||
CreateAnnouncementRequest,
|
||||
UpdateAnnouncementRequest,
|
||||
} from '@/features/admin/api/adminAnnouncements'
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
@@ -39,42 +42,41 @@ const rules: FormRules = {
|
||||
{ required: true, message: '请输入公告标题', trigger: 'blur' },
|
||||
{ max: 255, message: '标题不能超过255个字符', trigger: 'blur' },
|
||||
],
|
||||
content: [
|
||||
{ required: true, message: '请输入公告内容', trigger: 'blur' },
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: '请选择公告分类', trigger: 'change' },
|
||||
],
|
||||
content: [{ required: true, message: '请输入公告内容', trigger: 'blur' }],
|
||||
category: [{ required: true, message: '请选择公告分类', trigger: 'change' }],
|
||||
}
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
return props.mode === 'create' ? '新建公告' : '编辑公告'
|
||||
})
|
||||
|
||||
watch(() => props.visible, (val) => {
|
||||
if (val) {
|
||||
if (props.mode === 'edit' && props.announcement) {
|
||||
formData.value = {
|
||||
title: props.announcement.title,
|
||||
content: props.announcement.content,
|
||||
category: props.announcement.category as any,
|
||||
priority: props.announcement.priority,
|
||||
is_pinned: props.announcement.is_pinned,
|
||||
is_important: props.announcement.is_important,
|
||||
}
|
||||
} else {
|
||||
formData.value = {
|
||||
title: '',
|
||||
content: '',
|
||||
category: 'notice',
|
||||
priority: 0,
|
||||
is_pinned: false,
|
||||
is_important: false,
|
||||
watch(
|
||||
() => props.visible,
|
||||
val => {
|
||||
if (val) {
|
||||
if (props.mode === 'edit' && props.announcement) {
|
||||
formData.value = {
|
||||
title: props.announcement.title,
|
||||
content: props.announcement.content,
|
||||
category: props.announcement.category as any,
|
||||
priority: props.announcement.priority,
|
||||
is_pinned: props.announcement.is_pinned,
|
||||
is_important: props.announcement.is_important,
|
||||
}
|
||||
} else {
|
||||
formData.value = {
|
||||
title: '',
|
||||
content: '',
|
||||
category: 'notice',
|
||||
priority: 0,
|
||||
is_pinned: false,
|
||||
is_important: false,
|
||||
}
|
||||
}
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
function handleClose() {
|
||||
emit('update:visible', false)
|
||||
@@ -93,18 +95,8 @@ async function handleSave() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="visible"
|
||||
:title="dialogTitle"
|
||||
width="800px"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-dialog :model-value="visible" :title="dialogTitle" width="800px" @close="handleClose">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="公告标题" prop="title">
|
||||
<el-input
|
||||
v-model="formData.title"
|
||||
@@ -144,7 +136,9 @@ async function handleSave() {
|
||||
:max="999"
|
||||
placeholder="数值越大越靠前"
|
||||
/>
|
||||
<span style="margin-left: 12px; color: #909399; font-size: 13px">数值越大越靠前,默认为0</span>
|
||||
<span style="margin-left: 12px; color: #909399; font-size: 13px"
|
||||
>数值越大越靠前,默认为0</span
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标记">
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { fetchPermissions, fetchRole, assignRolePermissions, type Permission, type Role } from '@/features/admin/api/adminRoles'
|
||||
import {
|
||||
fetchPermissions,
|
||||
fetchRole,
|
||||
assignRolePermissions,
|
||||
type Permission,
|
||||
type Role,
|
||||
} from '@/features/admin/api/adminRoles'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
@@ -24,13 +30,16 @@ const groupedPermissions = ref<Record<string, Permission[]>>({})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (val) => {
|
||||
async val => {
|
||||
if (val && props.role) {
|
||||
loading.value = true
|
||||
try {
|
||||
const [perms, roleDetail] = await Promise.all([fetchPermissions(), fetchRole(props.role.id)])
|
||||
const [perms, roleDetail] = await Promise.all([
|
||||
fetchPermissions(),
|
||||
fetchRole(props.role.id),
|
||||
])
|
||||
allPermissions.value = perms
|
||||
selectedPermIds.value = (roleDetail.permissions || []).map((p) => p.id)
|
||||
selectedPermIds.value = (roleDetail.permissions || []).map(p => p.id)
|
||||
|
||||
// 按 resource 分组
|
||||
const grouped: Record<string, Permission[]> = {}
|
||||
@@ -45,7 +54,7 @@ watch(
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
async function handleSave() {
|
||||
@@ -64,10 +73,10 @@ async function handleSave() {
|
||||
}
|
||||
|
||||
function toggleGroup(perms: Permission[]) {
|
||||
const ids = perms.map((p) => p.id)
|
||||
const allSelected = ids.every((id) => selectedPermIds.value.includes(id))
|
||||
const ids = perms.map(p => p.id)
|
||||
const allSelected = ids.every(id => selectedPermIds.value.includes(id))
|
||||
if (allSelected) {
|
||||
selectedPermIds.value = selectedPermIds.value.filter((id) => !ids.includes(id))
|
||||
selectedPermIds.value = selectedPermIds.value.filter(id => !ids.includes(id))
|
||||
} else {
|
||||
const newIds = [...selectedPermIds.value]
|
||||
for (const id of ids) {
|
||||
@@ -78,11 +87,11 @@ function toggleGroup(perms: Permission[]) {
|
||||
}
|
||||
|
||||
function isGroupAllSelected(perms: Permission[]) {
|
||||
return perms.length > 0 && perms.every((p) => selectedPermIds.value.includes(p.id))
|
||||
return perms.length > 0 && perms.every(p => selectedPermIds.value.includes(p.id))
|
||||
}
|
||||
|
||||
function isGroupPartial(perms: Permission[]) {
|
||||
return perms.some((p) => selectedPermIds.value.includes(p.id)) && !isGroupAllSelected(perms)
|
||||
return perms.some(p => selectedPermIds.value.includes(p.id)) && !isGroupAllSelected(perms)
|
||||
}
|
||||
|
||||
function readError(error: unknown, fallback: string) {
|
||||
|
||||
@@ -22,19 +22,19 @@ const selectedRoleIds = ref<number[]>([])
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (val) => {
|
||||
async val => {
|
||||
if (val && props.admin) {
|
||||
loading.value = true
|
||||
try {
|
||||
allRoles.value = await fetchRoles()
|
||||
selectedRoleIds.value = props.admin.roles.map((r) => r.id)
|
||||
selectedRoleIds.value = props.admin.roles.map(r => r.id)
|
||||
} catch {
|
||||
ElMessage.error('加载角色列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
async function handleSave() {
|
||||
|
||||
@@ -21,7 +21,7 @@ const description = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
value.value = props.config.value || ''
|
||||
description.value = props.config.description || ''
|
||||
@@ -38,7 +38,7 @@ const isStructuredConfig = computed(() => {
|
||||
const selectOptions = computed<SystemConfigOption[] | null>(() => {
|
||||
const options = getSystemConfigSelectOptions(props.config.key)
|
||||
if (!options) return null
|
||||
if (!value.value || options.some((item) => item.value === value.value)) {
|
||||
if (!value.value || options.some(item => item.value === value.value)) {
|
||||
return options
|
||||
}
|
||||
return [{ label: `当前值:${value.value}`, value: value.value }, ...options]
|
||||
@@ -78,7 +78,9 @@ function readError(error: unknown, fallback: string) {
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
|
||||
<el-form-item v-if="isStructuredConfig" label="配置值 (JSON)" class="full-control">
|
||||
<el-input v-model="value" type="textarea" :rows="12" placeholder="配置值 JSON" />
|
||||
|
||||
@@ -22,7 +22,7 @@ const homeAnnouncementLines = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
homeAnnouncementLines.value = itemsToLines(parseHomeAnnouncements(props.config.value))
|
||||
description.value = props.config.description || ''
|
||||
@@ -39,7 +39,7 @@ function parseHomeAnnouncements(raw: string) {
|
||||
function linesToItems(value: string) {
|
||||
return value
|
||||
.split('\n')
|
||||
.map((item) => item.trim())
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
@@ -86,7 +86,9 @@ function readError(error: unknown, fallback: string) {
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
|
||||
<div class="home-config-editor">
|
||||
<div class="editor-toolbar">
|
||||
|
||||
@@ -3,7 +3,11 @@ import { ElMessage } from 'element-plus'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { uploadAdminFile } from '@/shared/api/files'
|
||||
import { defaultHomeBanners, mergeHomeConfig, type HomeBannerSlide } from '@/features/listings/api/homeConfig'
|
||||
import {
|
||||
defaultHomeBanners,
|
||||
mergeHomeConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { updateSystemConfig, type SystemConfig } from '@/features/admin/api/systemConfigs'
|
||||
import { safeParseJSON } from '@/utils/json'
|
||||
|
||||
@@ -24,7 +28,7 @@ const uploadingBannerIndex = ref<number | null>(null)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
homeBannersDraft.value = parseHomeBanners(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
@@ -88,7 +92,7 @@ async function handleSave() {
|
||||
submitting.value = true
|
||||
try {
|
||||
const value = JSON.stringify(
|
||||
homeBannersDraft.value.filter((item) => item.title.trim() || item.image_url?.trim()),
|
||||
homeBannersDraft.value.filter(item => item.title.trim() || item.image_url?.trim()),
|
||||
null,
|
||||
2
|
||||
)
|
||||
@@ -123,7 +127,9 @@ function readError(error: unknown, fallback: string) {
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
|
||||
<div class="home-config-editor">
|
||||
<div class="editor-toolbar">
|
||||
@@ -154,16 +160,24 @@ function readError(error: unknown, fallback: string) {
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="眉标" min-width="160">
|
||||
<template #default="{ row }"><el-input v-model="row.eyebrow" placeholder="如 三角洲行动账号专区" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.eyebrow" placeholder="如 三角洲行动账号专区"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主标题" min-width="220">
|
||||
<template #default="{ row }"><el-input v-model="row.title" placeholder="轮播主文案" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.title" placeholder="轮播主文案"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="角标" width="110">
|
||||
<template #default="{ row }"><el-input v-model="row.badge" placeholder="HOT" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.badge" placeholder="HOT"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="胶囊文案" min-width="220">
|
||||
<template #default="{ row }"><el-input v-model="row.pill" placeholder="底部补充文案" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.pill" placeholder="底部补充文案"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="色调" width="130">
|
||||
<template #default="{ row }">
|
||||
@@ -176,7 +190,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeHomeBanner($index)">删除</el-button>
|
||||
<el-button size="small" type="danger" plain @click="removeHomeBanner($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@@ -63,25 +63,37 @@ const draft = ref<ListingPublishAgreements>(cloneAgreements(defaultListingPublis
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
draft.value = parseListingPublishAgreements(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function parseListingPublishAgreements(raw: string) {
|
||||
const parsed = safeParseJSON(raw, defaultListingPublishAgreements)
|
||||
return cloneAgreements({
|
||||
virtual_asset_sale: {
|
||||
title: readText(parsed?.virtual_asset_sale?.title, defaultListingPublishAgreements.virtual_asset_sale.title),
|
||||
content: readText(parsed?.virtual_asset_sale?.content, defaultListingPublishAgreements.virtual_asset_sale.content),
|
||||
title: readText(
|
||||
parsed?.virtual_asset_sale?.title,
|
||||
defaultListingPublishAgreements.virtual_asset_sale.title
|
||||
),
|
||||
content: readText(
|
||||
parsed?.virtual_asset_sale?.content,
|
||||
defaultListingPublishAgreements.virtual_asset_sale.content
|
||||
),
|
||||
},
|
||||
seller_agreement: {
|
||||
title: readText(parsed?.seller_agreement?.title, defaultListingPublishAgreements.seller_agreement.title),
|
||||
content: readText(parsed?.seller_agreement?.content, defaultListingPublishAgreements.seller_agreement.content),
|
||||
title: readText(
|
||||
parsed?.seller_agreement?.title,
|
||||
defaultListingPublishAgreements.seller_agreement.title
|
||||
),
|
||||
content: readText(
|
||||
parsed?.seller_agreement?.content,
|
||||
defaultListingPublishAgreements.seller_agreement.content
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -133,7 +145,9 @@ function readError(error: unknown, fallback: string) {
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<div class="dialog-header">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
<el-button size="small" @click="resetDefaults">恢复默认文本</el-button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -63,25 +63,37 @@ const draft = ref<OrderAgreements>(cloneAgreements(defaultOrderAgreements))
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
draft.value = parseOrderAgreements(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function parseOrderAgreements(raw: string) {
|
||||
const parsed = safeParseJSON(raw, defaultOrderAgreements)
|
||||
return cloneAgreements({
|
||||
virtual_asset_purchase: {
|
||||
title: readText(parsed?.virtual_asset_purchase?.title, defaultOrderAgreements.virtual_asset_purchase.title),
|
||||
content: readText(parsed?.virtual_asset_purchase?.content, defaultOrderAgreements.virtual_asset_purchase.content),
|
||||
title: readText(
|
||||
parsed?.virtual_asset_purchase?.title,
|
||||
defaultOrderAgreements.virtual_asset_purchase.title
|
||||
),
|
||||
content: readText(
|
||||
parsed?.virtual_asset_purchase?.content,
|
||||
defaultOrderAgreements.virtual_asset_purchase.content
|
||||
),
|
||||
},
|
||||
renter_agreement: {
|
||||
title: readText(parsed?.renter_agreement?.title, defaultOrderAgreements.renter_agreement.title),
|
||||
content: readText(parsed?.renter_agreement?.content, defaultOrderAgreements.renter_agreement.content),
|
||||
title: readText(
|
||||
parsed?.renter_agreement?.title,
|
||||
defaultOrderAgreements.renter_agreement.title
|
||||
),
|
||||
content: readText(
|
||||
parsed?.renter_agreement?.content,
|
||||
defaultOrderAgreements.renter_agreement.content
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -134,7 +146,9 @@ function readError(error: unknown, fallback: string) {
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<div class="dialog-header">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
<el-button size="small" @click="resetDefaults">恢复默认文本</el-button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -86,12 +86,7 @@ const isLakala = computed(() => formData.value.provider === 'lakala')
|
||||
const isMock = computed(() => formData.value.provider === 'mock')
|
||||
const signKeyLabel = computed(() => (isLakala.value ? '商户私钥' : '签名密钥'))
|
||||
const notifyKeyLabel = computed(() => (isLakala.value ? '通知证书' : '通知密钥'))
|
||||
const extraConfig = computed<Record<string, any>>(() => {
|
||||
if (!formData.value.extra_config) {
|
||||
formData.value.extra_config = {}
|
||||
}
|
||||
return formData.value.extra_config
|
||||
})
|
||||
const extraConfig = computed<Record<string, any>>(() => formData.value.extra_config || {})
|
||||
|
||||
function normalizeExtraConfig(provider: string, extraConfig?: Record<string, any> | null) {
|
||||
const extra = {
|
||||
@@ -106,7 +101,7 @@ function normalizeExtraConfig(provider: string, extraConfig?: Record<string, any
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val && props.config) {
|
||||
formData.value = {
|
||||
name: props.config.name,
|
||||
@@ -218,7 +213,11 @@ function handleClose() {
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付服务商" required>
|
||||
<el-select v-model="formData.provider" :disabled="mode !== 'create'" @change="handleProviderChange">
|
||||
<el-select
|
||||
v-model="formData.provider"
|
||||
:disabled="mode !== 'create'"
|
||||
@change="handleProviderChange"
|
||||
>
|
||||
<el-option label="乐刷支付" value="leshua" />
|
||||
<el-option label="拉卡拉支付" value="lakala" />
|
||||
<el-option label="模拟支付" value="mock" />
|
||||
@@ -234,11 +233,19 @@ function handleClose() {
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isLakala" label="App ID" required>
|
||||
<el-input v-model="extraConfig.app_id" placeholder="拉卡拉开放平台 appId" :disabled="isReadonly" />
|
||||
<el-input
|
||||
v-model="extraConfig.app_id"
|
||||
placeholder="拉卡拉开放平台 appId"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isLakala" label="证书序列号" required>
|
||||
<el-input v-model="extraConfig.serial_no" placeholder="商户证书序列号" :disabled="isReadonly" />
|
||||
<el-input
|
||||
v-model="extraConfig.serial_no"
|
||||
placeholder="商户证书序列号"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isLakala" label="终端号" required>
|
||||
@@ -251,7 +258,9 @@ function handleClose() {
|
||||
:type="isLakala ? 'textarea' : 'password'"
|
||||
:rows="isLakala ? 5 : undefined"
|
||||
:show-password="!isLakala"
|
||||
:placeholder="mode === 'edit' ? '留空则不修改' : isLakala ? '请输入商户私钥 PEM' : '请输入签名密钥'"
|
||||
:placeholder="
|
||||
mode === 'edit' ? '留空则不修改' : isLakala ? '请输入商户私钥 PEM' : '请输入签名密钥'
|
||||
"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -262,7 +271,13 @@ function handleClose() {
|
||||
:type="isLakala ? 'textarea' : 'password'"
|
||||
:rows="isLakala ? 5 : undefined"
|
||||
:show-password="!isLakala"
|
||||
:placeholder="mode === 'edit' ? '留空则不修改' : isLakala ? '请输入拉卡拉通知验签证书 PEM' : '请输入通知密钥'"
|
||||
:placeholder="
|
||||
mode === 'edit'
|
||||
? '留空则不修改'
|
||||
: isLakala
|
||||
? '请输入拉卡拉通知验签证书 PEM'
|
||||
: '请输入通知密钥'
|
||||
"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -282,7 +297,11 @@ function handleClose() {
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="!isMock" label="回调地址" required>
|
||||
<el-input v-model="formData.notify_url" placeholder="异步通知回调地址" :disabled="isReadonly" />
|
||||
<el-input
|
||||
v-model="formData.notify_url"
|
||||
placeholder="异步通知回调地址"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否默认">
|
||||
@@ -312,7 +331,11 @@ function handleClose() {
|
||||
</template>
|
||||
|
||||
<el-form-item label="跳转地址">
|
||||
<el-input v-model="formData.jump_url" placeholder="支付完成跳转地址" :disabled="isReadonly" />
|
||||
<el-input
|
||||
v-model="formData.jump_url"
|
||||
placeholder="支付完成跳转地址"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付方式">
|
||||
@@ -332,7 +355,12 @@ function handleClose() {
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isLakala" label="有效期分钟">
|
||||
<el-input-number v-model="extraConfig.order_expire_minutes" :min="1" :max="1440" :disabled="isReadonly" />
|
||||
<el-input-number
|
||||
v-model="extraConfig.order_expire_minutes"
|
||||
:min="1"
|
||||
:max="1440"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付形态">
|
||||
|
||||
@@ -63,13 +63,13 @@ const draft = ref<PostRentalNotice>(cloneNotice(defaultPostRentalNotice))
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
draft.value = parsePostRentalNotice(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function parsePostRentalNotice(raw: string) {
|
||||
@@ -128,7 +128,9 @@ function readError(error: unknown, fallback: string) {
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<div class="dialog-header">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
<el-button size="small" @click="resetDefaults">恢复默认文本</el-button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const publishOptionsDraft = ref<ListingPublishOptions>(cloneOptions(emptyListing
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
publishOptionsDraft.value = parsePublishOptions(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
@@ -47,7 +47,7 @@ function cloneOptions(options: ListingPublishOptions) {
|
||||
function linesToItems(value: string) {
|
||||
return value
|
||||
.split('\n')
|
||||
.map((item) => item.trim())
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
@@ -200,7 +200,9 @@ function readError(error: unknown, fallback: string) {
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
|
||||
<div class="publish-options-editor">
|
||||
<div class="editor-toolbar">
|
||||
@@ -300,7 +302,12 @@ function readError(error: unknown, fallback: string) {
|
||||
<strong>发布规则</strong>
|
||||
</div>
|
||||
<el-form-item label="最低烽火等级">
|
||||
<el-input-number v-model="publishOptionsDraft.fire_level_min" :min="1" :step="1" class="full-control" />
|
||||
<el-input-number
|
||||
v-model="publishOptionsDraft.fire_level_min"
|
||||
:min="1"
|
||||
:step="1"
|
||||
class="full-control"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
@@ -309,7 +316,11 @@ function readError(error: unknown, fallback: string) {
|
||||
<strong>押金与价格提示</strong>
|
||||
</div>
|
||||
<el-form-item label="押金提示">
|
||||
<el-input v-model="publishOptionsDraft.price_config.deposit_placeholder" type="textarea" :rows="3" />
|
||||
<el-input
|
||||
v-model="publishOptionsDraft.price_config.deposit_placeholder"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="押金后缀">
|
||||
<el-input
|
||||
@@ -319,10 +330,16 @@ function readError(error: unknown, fallback: string) {
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格提示">
|
||||
<el-input v-model="publishOptionsDraft.price_config.price_placeholder" class="full-control" />
|
||||
<el-input
|
||||
v-model="publishOptionsDraft.price_config.price_placeholder"
|
||||
class="full-control"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="比例说明">
|
||||
<el-input v-model="publishOptionsDraft.price_config.ratio_description" class="full-control" />
|
||||
<el-input
|
||||
v-model="publishOptionsDraft.price_config.ratio_description"
|
||||
class="full-control"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
@@ -339,19 +356,35 @@ function readError(error: unknown, fallback: string) {
|
||||
class="full-control"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-table :data="publishOptionsDraft.deposit_recommend_config.skin_group_rules" size="small" border>
|
||||
<el-table
|
||||
:data="publishOptionsDraft.deposit_recommend_config.skin_group_rules"
|
||||
size="small"
|
||||
border
|
||||
>
|
||||
<el-table-column label="皮肤分组 Key" min-width="150">
|
||||
<template #default="{ row }"><el-input v-model="row.group_key" placeholder="operatorRed" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.group_key" placeholder="operatorRed"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="140">
|
||||
<template #default="{ row }"><el-input v-model="row.label" placeholder="干员红皮" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.label" placeholder="干员红皮"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="每个增加押金" min-width="140">
|
||||
<template #default="{ row }"><el-input-number v-model="row.amount_per_item" :min="0" :step="5" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.amount_per_item" :min="0" :step="5"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeDepositSkinGroupRule($index)">删除</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
@click="removeDepositSkinGroupRule($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -365,16 +398,30 @@ function readError(error: unknown, fallback: string) {
|
||||
<span>保险基础比例</span>
|
||||
<el-button size="small" @click="addInsuranceBaseRatio">添加保险比例</el-button>
|
||||
</div>
|
||||
<el-table :data="publishOptionsDraft.ratio_config.insurance_base_ratios" size="small" border>
|
||||
<el-table
|
||||
:data="publishOptionsDraft.ratio_config.insurance_base_ratios"
|
||||
size="small"
|
||||
border
|
||||
>
|
||||
<el-table-column label="保险" min-width="160">
|
||||
<template #default="{ row }"><el-input v-model="row.insurance" placeholder="3*3" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input v-model="row.insurance" placeholder="3*3"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="基础比例" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.ratio" :min="0" :step="0.5" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.ratio" :min="0" :step="0.5"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeInsuranceBaseRatio($index)">删除</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
@click="removeInsuranceBaseRatio($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -403,11 +450,15 @@ function readError(error: unknown, fallback: string) {
|
||||
<template #default="{ row }"><el-input v-model="row.group_key" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="缺失加成" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.missing_penalty" :min="0" :step="0.5" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.missing_penalty" :min="0" :step="0.5"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeRatioConfigItem($index)">删除</el-button>
|
||||
<el-button size="small" type="danger" plain @click="removeRatioConfigItem($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -418,14 +469,20 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<el-table :data="publishOptionsDraft.ratio_config.coin_corrections" size="small" border>
|
||||
<el-table-column label="大于 M" min-width="130">
|
||||
<template #default="{ row }"><el-input-number v-model="row.threshold_m" :min="0" :step="10" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.threshold_m" :min="0" :step="10"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="比例加成" min-width="130">
|
||||
<template #default="{ row }"><el-input-number v-model="row.correction" :min="0" :step="0.5" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.correction" :min="0" :step="0.5"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeCoinCorrection($index)">删除</el-button>
|
||||
<el-button size="small" type="danger" plain @click="removeCoinCorrection($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -436,7 +493,11 @@ function readError(error: unknown, fallback: string) {
|
||||
<strong>皮肤分类</strong>
|
||||
<el-button size="small" @click="addSkinGroup">添加分类</el-button>
|
||||
</div>
|
||||
<div v-for="(group, index) in publishOptionsDraft.skin_groups" :key="`${group.key}-${index}`" class="skin-config-row">
|
||||
<div
|
||||
v-for="(group, index) in publishOptionsDraft.skin_groups"
|
||||
:key="`${group.key}-${index}`"
|
||||
class="skin-config-row"
|
||||
>
|
||||
<el-input v-model="group.key" placeholder="分类 key" />
|
||||
<el-input v-model="group.title" placeholder="分类名称" />
|
||||
<el-input
|
||||
@@ -470,7 +531,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeQuantityItem($index)">删除</el-button>
|
||||
<el-button size="small" type="danger" plain @click="removeQuantityItem($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -496,7 +559,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeScreenshotSlot($index)">删除</el-button>
|
||||
<el-button size="small" type="danger" plain @click="removeScreenshotSlot($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@@ -29,14 +29,17 @@ const form = ref({
|
||||
is_global: false,
|
||||
})
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
visible.value = val
|
||||
if (val) {
|
||||
loadReplies()
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
val => {
|
||||
visible.value = val
|
||||
if (val) {
|
||||
loadReplies()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
watch(visible, (val) => {
|
||||
watch(visible, val => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
@@ -76,7 +79,12 @@ async function handleSubmit() {
|
||||
await updateQuickReply(editingId.value, form.value)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createQuickReply(form.value.title, form.value.content, form.value.sort_order, form.value.is_global)
|
||||
await createQuickReply(
|
||||
form.value.title,
|
||||
form.value.content,
|
||||
form.value.sort_order,
|
||||
form.value.is_global
|
||||
)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
resetForm()
|
||||
@@ -100,7 +108,9 @@ async function handleDelete(reply: QuickReply) {
|
||||
ElMessage.success('删除成功')
|
||||
await loadReplies()
|
||||
emit('success')
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { createRole, updateRole, type Role, type CreateRoleRequest, type UpdateRoleRequest } from '@/features/admin/api/adminRoles'
|
||||
import {
|
||||
createRole,
|
||||
updateRole,
|
||||
type Role,
|
||||
type CreateRoleRequest,
|
||||
type UpdateRoleRequest,
|
||||
} from '@/features/admin/api/adminRoles'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
@@ -25,7 +31,7 @@ const isEdit = ref(false)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
if (props.role) {
|
||||
isEdit.value = true
|
||||
@@ -40,7 +46,7 @@ watch(
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
async function handleSave() {
|
||||
|
||||
@@ -22,11 +22,13 @@ const emit = defineEmits<{
|
||||
|
||||
const submitting = ref(false)
|
||||
const description = ref('')
|
||||
const salePriceConfigDraft = ref<PublishSalePriceConfig>(cloneSalePriceConfig(emptyListingSalePriceConfig))
|
||||
const salePriceConfigDraft = ref<PublishSalePriceConfig>(
|
||||
cloneSalePriceConfig(emptyListingSalePriceConfig)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
salePriceConfigDraft.value = parseSalePriceConfig(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
@@ -103,7 +105,9 @@ function readError(error: unknown, fallback: string) {
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-body">
|
||||
<p class="config-key-label"><strong>{{ config.key }}</strong></p>
|
||||
<p class="config-key-label">
|
||||
<strong>{{ config.key }}</strong>
|
||||
</p>
|
||||
|
||||
<div class="publish-options-editor">
|
||||
<div class="editor-toolbar">
|
||||
@@ -117,17 +121,29 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<el-table :data="salePriceConfigDraft.fixed_markup_rules" size="small" border>
|
||||
<el-table-column label="最小 M" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.min_m" :min="0" :step="10" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.min_m" :min="0" :step="10"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最大 M" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.max_m" :min="0" :step="10" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.max_m" :min="0" :step="10"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="加价金额/元" min-width="140">
|
||||
<template #default="{ row }"><el-input-number v-model="row.markup_amount" :min="0" :step="1" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.markup_amount" :min="0" :step="1"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeSaleFixedMarkupRule($index)">删除</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
@click="removeSaleFixedMarkupRule($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -138,17 +154,29 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<el-table :data="salePriceConfigDraft.ratio_adjustment_rules" size="small" border>
|
||||
<el-table-column label="最小 M" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.min_m" :min="0" :step="10" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.min_m" :min="0" :step="10"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最大 M" min-width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.max_m" :min="0" :step="10" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.max_m" :min="0" :step="10"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="比例修正" min-width="130">
|
||||
<template #default="{ row }"><el-input-number v-model="row.ratio_subtract" :min="0" :step="0.5" /></template>
|
||||
<template #default="{ row }"
|
||||
><el-input-number v-model="row.ratio_subtract" :min="0" :step="0.5"
|
||||
/></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="{ $index }">
|
||||
<el-button size="small" type="danger" plain @click="removeSaleRatioAdjustmentRule($index)">删除</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
@click="removeSaleRatioAdjustmentRule($index)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@@ -51,14 +51,17 @@ function getSupportStatusColor(status: string) {
|
||||
return colors[status] || '#9ca3af'
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
visible.value = val
|
||||
if (val) {
|
||||
loadAdmins()
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
val => {
|
||||
visible.value = val
|
||||
if (val) {
|
||||
loadAdmins()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
watch(visible, (val) => {
|
||||
watch(visible, val => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
@@ -112,7 +115,10 @@ function getStatusTag(count: number) {
|
||||
<div class="admin-info">
|
||||
<div class="admin-avatar-wrap">
|
||||
<el-avatar :size="36" :icon="User" />
|
||||
<span class="status-indicator" :style="{ backgroundColor: getSupportStatusColor(admin.support_status) }"></span>
|
||||
<span
|
||||
class="status-indicator"
|
||||
:style="{ backgroundColor: getSupportStatusColor(admin.support_status) }"
|
||||
></span>
|
||||
</div>
|
||||
<div class="admin-detail">
|
||||
<span class="admin-name">{{ admin.nickname }}</span>
|
||||
@@ -120,7 +126,10 @@ function getStatusTag(count: number) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-status">
|
||||
<span class="support-status" :style="{ color: getSupportStatusColor(admin.support_status) }">
|
||||
<span
|
||||
class="support-status"
|
||||
:style="{ color: getSupportStatusColor(admin.support_status) }"
|
||||
>
|
||||
{{ getSupportStatusLabel(admin.support_status) }}
|
||||
</span>
|
||||
<span class="admin-count">{{ admin.chat_count }} 个会话</span>
|
||||
@@ -131,7 +140,12 @@ function getStatusTag(count: number) {
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" :disabled="!selectedAdminId" @click="handleSubmit">
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="submitting"
|
||||
:disabled="!selectedAdminId"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
确认转接
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
@@ -62,7 +62,7 @@ async function handleConfirmPayment() {
|
||||
cancelButtonText: '取消',
|
||||
inputType: 'textarea',
|
||||
inputPlaceholder: '输入打款备注...',
|
||||
inputValidator: (value) => {
|
||||
inputValidator: value => {
|
||||
return value && value.trim().length > 0
|
||||
},
|
||||
inputErrorMessage: '请输入打款备注',
|
||||
@@ -97,10 +97,15 @@ function statusLabel(status: string) {
|
||||
}
|
||||
|
||||
function statusType(status: string) {
|
||||
return status === 'completed' ? 'success' :
|
||||
status === 'pending' ? 'warning' :
|
||||
status === 'processing' ? 'primary' :
|
||||
status === 'rejected' ? 'danger' : 'info'
|
||||
return status === 'completed'
|
||||
? 'success'
|
||||
: status === 'pending'
|
||||
? 'warning'
|
||||
: status === 'processing'
|
||||
? 'primary'
|
||||
: status === 'rejected'
|
||||
? 'danger'
|
||||
: 'info'
|
||||
}
|
||||
|
||||
function accountTypeLabel(type: string) {
|
||||
@@ -188,7 +193,11 @@ function accountTypeLabel(type: string) {
|
||||
<el-descriptions-item v-if="withdrawal.bank_branch" label="开户支行">
|
||||
{{ withdrawal.bank_branch }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="withdrawal.certificate_urls && withdrawal.certificate_urls.length > 0" label="收款二维码" :span="2">
|
||||
<el-descriptions-item
|
||||
v-if="withdrawal.certificate_urls && withdrawal.certificate_urls.length > 0"
|
||||
label="收款二维码"
|
||||
:span="2"
|
||||
>
|
||||
<div style="display: flex; gap: 8px; flex-wrap: wrap">
|
||||
<el-image
|
||||
v-for="(url, idx) in withdrawal.certificate_urls"
|
||||
@@ -299,9 +308,7 @@ function accountTypeLabel(type: string) {
|
||||
确认打款
|
||||
</el-button>
|
||||
</div>
|
||||
<el-button @click="emit('update:modelValue', false)">
|
||||
关闭
|
||||
</el-button>
|
||||
<el-button @click="emit('update:modelValue', false)"> 关闭 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
Reference in New Issue
Block a user