feat(admin): 客服手动录单支持平台与操作人,并可后台配置可选项
- 录单列表新增「平台」「操作人」两列,录单表单与编辑弹窗新增同名字段下拉 - 新增 cs_manual_entry_options 表与 4 个接口(读取/新增/重命名/删除),页面右上角弹窗维护平台与操作人 - 迁移 000087:cs_manual_entries 增加 platform/operator 列与索引,注册 cs_manual_entry:option_manage 权限并授予 ops/super_admin - 记录保存名称快照,删除选项不影响历史记录;同类型重名返回 409,跨类型同名允许 - 顶部关键词查询支持命中平台/操作人 - 新增单测:选项 CRUD 边界与录单平台/操作人读写
This commit is contained in:
@@ -2,9 +2,14 @@ import { apiClient } from '@/shared/api/client'
|
||||
|
||||
import type { ApiResponse, PaginatedResult } from '@/shared/types/types'
|
||||
|
||||
/** 录单可选项类型:平台 / 操作人 */
|
||||
export type ManualEntryOptionType = 'platform' | 'operator'
|
||||
|
||||
export interface ManualEntryItem {
|
||||
id: number
|
||||
entry_no: string
|
||||
platform: string
|
||||
operator: string
|
||||
admin_id: number
|
||||
admin_name: string
|
||||
admin_username: string
|
||||
@@ -12,6 +17,19 @@ export interface ManualEntryItem {
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface ManualEntryOption {
|
||||
id: number
|
||||
type: ManualEntryOptionType
|
||||
name: string
|
||||
sort_order: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface ManualEntryOptions {
|
||||
platforms: ManualEntryOption[]
|
||||
operators: ManualEntryOption[]
|
||||
}
|
||||
|
||||
export interface ManualEntryAgentStats {
|
||||
admin_id: number
|
||||
admin_name: string
|
||||
@@ -20,11 +38,15 @@ export interface ManualEntryAgentStats {
|
||||
|
||||
export interface CreateManualEntryRequest {
|
||||
entry_no: string
|
||||
platform?: string
|
||||
operator?: string
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export interface UpdateManualEntryRequest {
|
||||
entry_no: string
|
||||
platform?: string
|
||||
operator?: string
|
||||
remark?: string
|
||||
}
|
||||
|
||||
@@ -79,3 +101,37 @@ export async function fetchManualEntryTodayStats() {
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
/** 获取平台 / 操作人可选项(录单下拉数据源) */
|
||||
export async function fetchManualEntryOptions() {
|
||||
const { data } = await apiClient.get<ApiResponse<ManualEntryOptions>>(
|
||||
'/admin/manual-entries/options'
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function createManualEntryOption(payload: {
|
||||
type: ManualEntryOptionType
|
||||
name: string
|
||||
}) {
|
||||
const { data } = await apiClient.post<ApiResponse<ManualEntryOption>>(
|
||||
'/admin/manual-entries/options',
|
||||
payload
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function updateManualEntryOption(id: number, name: string) {
|
||||
const { data } = await apiClient.put<ApiResponse<ManualEntryOption>>(
|
||||
`/admin/manual-entries/options/${id}`,
|
||||
{ name }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function deleteManualEntryOption(id: number) {
|
||||
const { data } = await apiClient.delete<ApiResponse<{ deleted: boolean }>>(
|
||||
`/admin/manual-entries/options/${id}`
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.page-header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.manual-entry-form-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
@@ -34,19 +40,22 @@
|
||||
|
||||
.manual-entry-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.manual-entry-form-grid :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.manual-entry-submit {
|
||||
.full-control {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.manual-entry-submit-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.manual-entry-filter-row {
|
||||
@@ -62,7 +71,7 @@
|
||||
}
|
||||
|
||||
.filter-keyword {
|
||||
width: 260px;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
.filter-date {
|
||||
@@ -76,8 +85,87 @@
|
||||
color: #1e3a8a;
|
||||
}
|
||||
|
||||
/* 平台 / 操作人配置弹窗 */
|
||||
.option-config-tip {
|
||||
margin: 0 0 16px;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.option-config-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.option-config-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.option-config-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.option-config-add {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.option-config-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.option-config-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 8px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.option-config-name {
|
||||
font-size: 13px;
|
||||
color: #0f172a;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.option-config-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.option-config-actions :deep(.el-button) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.option-config-empty {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.manual-entry-form-grid {
|
||||
.manual-entry-form-grid,
|
||||
.option-config-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
import {
|
||||
createManualEntry,
|
||||
createManualEntryOption,
|
||||
deleteManualEntry,
|
||||
deleteManualEntryOption,
|
||||
fetchManualEntries,
|
||||
fetchManualEntryOptions,
|
||||
updateManualEntry,
|
||||
updateManualEntryOption,
|
||||
type ManualEntryItem,
|
||||
type ManualEntryOption,
|
||||
type ManualEntryOptionType,
|
||||
type ManualEntryOptions,
|
||||
} from '@/features/admin/api/adminManualEntry'
|
||||
import { useAdminPaginatedTable } from '@/features/admin/composables/useAdminPaginatedTable'
|
||||
import { useAdminSessionStore } from '@/stores/adminSession'
|
||||
@@ -21,6 +28,7 @@ const currentAdminName = computed(() => adminSession.nickname || adminSession.us
|
||||
const canCreate = computed(() => adminSession.hasPermission('cs_manual_entry:create'))
|
||||
const canUpdate = computed(() => adminSession.hasPermission('cs_manual_entry:update'))
|
||||
const canDelete = computed(() => adminSession.hasPermission('cs_manual_entry:delete'))
|
||||
const canManageOptions = computed(() => adminSession.hasPermission('cs_manual_entry:option_manage'))
|
||||
|
||||
const filters = reactive({
|
||||
keyword: '',
|
||||
@@ -28,8 +36,13 @@ const filters = reactive({
|
||||
dateRange: null as string[] | null,
|
||||
})
|
||||
|
||||
const options = ref<ManualEntryOptions>({ platforms: [], operators: [] })
|
||||
const optionsLoading = ref(false)
|
||||
|
||||
const entryForm = reactive({
|
||||
entry_no: '',
|
||||
platform: '',
|
||||
operator: '',
|
||||
remark: '',
|
||||
})
|
||||
|
||||
@@ -54,6 +67,21 @@ const {
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
void loadOptions()
|
||||
})
|
||||
|
||||
async function loadOptions() {
|
||||
optionsLoading.value = true
|
||||
try {
|
||||
options.value = await fetchManualEntryOptions()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '获取平台与操作人选项失败'))
|
||||
} finally {
|
||||
optionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetFilters() {
|
||||
filters.keyword = ''
|
||||
filters.entry_no = ''
|
||||
@@ -86,10 +114,14 @@ async function handleCreate() {
|
||||
try {
|
||||
const result = await createManualEntry({
|
||||
entry_no: entryNo,
|
||||
platform: entryForm.platform,
|
||||
operator: entryForm.operator,
|
||||
remark: entryForm.remark,
|
||||
})
|
||||
ElMessage.success(`编号 ${result.entry.entry_no} 已登记到【${result.entry.admin_name}】`)
|
||||
entryForm.entry_no = ''
|
||||
entryForm.platform = ''
|
||||
entryForm.operator = ''
|
||||
entryForm.remark = ''
|
||||
currentPage.value = 1
|
||||
await loadEntries()
|
||||
@@ -104,11 +136,35 @@ async function handleCreate() {
|
||||
const editVisible = ref(false)
|
||||
const editSubmitting = ref(false)
|
||||
const editingEntry = ref<ManualEntryItem | null>(null)
|
||||
const editForm = reactive({ entry_no: '', remark: '' })
|
||||
const editForm = reactive({ entry_no: '', platform: '', operator: '', remark: '' })
|
||||
|
||||
/**
|
||||
* 历史记录里的平台/操作人可能已被后台删除选项,
|
||||
* 这里把当前值补进下拉,保证编辑时能正常显示与保留。
|
||||
*/
|
||||
function withCurrentValue(list: ManualEntryOption[], current: string) {
|
||||
const items: { id: number | string; name: string }[] = list.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
}))
|
||||
if (current && !items.some(item => item.name === current)) {
|
||||
items.unshift({ id: `current-${current}`, name: current })
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
const editPlatformOptions = computed(() =>
|
||||
withCurrentValue(options.value.platforms, editForm.platform)
|
||||
)
|
||||
const editOperatorOptions = computed(() =>
|
||||
withCurrentValue(options.value.operators, editForm.operator)
|
||||
)
|
||||
|
||||
function openEdit(row: ManualEntryItem) {
|
||||
editingEntry.value = row
|
||||
editForm.entry_no = row.entry_no
|
||||
editForm.platform = row.platform || ''
|
||||
editForm.operator = row.operator || ''
|
||||
editForm.remark = row.remark
|
||||
editVisible.value = true
|
||||
}
|
||||
@@ -124,6 +180,8 @@ async function handleUpdate() {
|
||||
try {
|
||||
await updateManualEntry(editingEntry.value.id, {
|
||||
entry_no: entryNo,
|
||||
platform: editForm.platform,
|
||||
operator: editForm.operator,
|
||||
remark: editForm.remark,
|
||||
})
|
||||
ElMessage.success('录单已更新')
|
||||
@@ -154,6 +212,86 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
ElMessage.error(readError(error, '删除失败'))
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 平台 / 操作人配置 ----------
|
||||
const configVisible = ref(false)
|
||||
const optionSubmitting = ref(false)
|
||||
const newPlatformName = ref('')
|
||||
const newOperatorName = ref('')
|
||||
|
||||
function openConfig() {
|
||||
configVisible.value = true
|
||||
if (!options.value.platforms.length && !options.value.operators.length) {
|
||||
void loadOptions()
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddOption(type: ManualEntryOptionType) {
|
||||
const name = (type === 'platform' ? newPlatformName.value : newOperatorName.value).trim()
|
||||
if (!name) {
|
||||
ElMessage.warning('请输入名称')
|
||||
return
|
||||
}
|
||||
optionSubmitting.value = true
|
||||
try {
|
||||
await createManualEntryOption({ type, name })
|
||||
if (type === 'platform') newPlatformName.value = ''
|
||||
else newOperatorName.value = ''
|
||||
ElMessage.success('已添加')
|
||||
await loadOptions()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '添加失败'))
|
||||
} finally {
|
||||
optionSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRenameOption(item: ManualEntryOption) {
|
||||
let input: string
|
||||
try {
|
||||
const result = await ElMessageBox.prompt('请输入新的名称', '重命名', {
|
||||
inputValue: item.name,
|
||||
inputPattern: /\S/,
|
||||
inputErrorMessage: '名称不能为空',
|
||||
confirmButtonText: '保存',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
input = result.value
|
||||
} catch {
|
||||
return // 用户取消
|
||||
}
|
||||
const name = input.trim()
|
||||
if (!name || name === item.name) return
|
||||
optionSubmitting.value = true
|
||||
try {
|
||||
await updateManualEntryOption(item.id, name)
|
||||
ElMessage.success('已重命名')
|
||||
await loadOptions()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '重命名失败'))
|
||||
} finally {
|
||||
optionSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRemoveOption(item: ManualEntryOption) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定删除${item.type === 'platform' ? '平台' : '操作人'}【${item.name}】吗?历史录单记录不受影响。`,
|
||||
'删除确认',
|
||||
{ confirmButtonText: '确认删除', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch {
|
||||
return // 用户取消
|
||||
}
|
||||
try {
|
||||
await deleteManualEntryOption(item.id)
|
||||
ElMessage.success('已删除')
|
||||
await loadOptions()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '删除失败'))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -165,9 +303,14 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
<p>
|
||||
当前登录客服:
|
||||
<strong>{{ currentAdminName }}</strong>
|
||||
· 输入编号登记到本人名下,记录登记时间,支持查询与修正。
|
||||
· 输入编号登记到本人名下,可选平台与操作人,支持查询与修正。
|
||||
</p>
|
||||
</div>
|
||||
<div class="page-header-actions">
|
||||
<el-button v-if="canManageOptions" :loading="optionsLoading" @click="openConfig">
|
||||
配置平台/操作人
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 录单表单 -->
|
||||
@@ -186,6 +329,40 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
@keyup.enter="handleCreate"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台(可选)">
|
||||
<el-select
|
||||
v-model="entryForm.platform"
|
||||
placeholder="请选择平台"
|
||||
clearable
|
||||
filterable
|
||||
class="full-control"
|
||||
:loading="optionsLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options.platforms"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人(可选)">
|
||||
<el-select
|
||||
v-model="entryForm.operator"
|
||||
placeholder="请选择操作人"
|
||||
clearable
|
||||
filterable
|
||||
class="full-control"
|
||||
:loading="optionsLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options.operators"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注(可选)">
|
||||
<el-input
|
||||
v-model="entryForm.remark"
|
||||
@@ -195,11 +372,9 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
@keyup.enter="handleCreate"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="manual-entry-submit">
|
||||
<el-button type="primary" :loading="submitting" @click="handleCreate">
|
||||
提交登记
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="manual-entry-submit-row">
|
||||
<el-button type="primary" :loading="submitting" @click="handleCreate"> 提交登记 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -215,7 +390,7 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
/>
|
||||
<el-input
|
||||
v-model="filters.keyword"
|
||||
placeholder="按编号 / 客服名 / 登录名模糊查询"
|
||||
placeholder="按编号 / 客服名 / 登录名 / 平台 / 操作人模糊查询"
|
||||
clearable
|
||||
class="filter-keyword"
|
||||
@keyup.enter="applySearch"
|
||||
@@ -235,11 +410,17 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
|
||||
<el-table v-loading="loading" class="table-panel" :data="entries">
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="entry_no" label="编号" min-width="160">
|
||||
<el-table-column prop="entry_no" label="编号" width="160">
|
||||
<template #default="{ row }">
|
||||
<span class="mono-entry-no">{{ row.entry_no }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="platform" label="平台" min-width="120">
|
||||
<template #default="{ row }">{{ row.platform || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" label="操作人" min-width="120">
|
||||
<template #default="{ row }">{{ row.operator || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="admin_name" label="客服" min-width="120">
|
||||
<template #default="{ row }">{{ row.admin_name || row.admin_username || '-' }}</template>
|
||||
</el-table-column>
|
||||
@@ -285,6 +466,38 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台">
|
||||
<el-select
|
||||
v-model="editForm.platform"
|
||||
placeholder="请选择平台"
|
||||
clearable
|
||||
filterable
|
||||
class="full-control"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editPlatformOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人">
|
||||
<el-select
|
||||
v-model="editForm.operator"
|
||||
placeholder="请选择操作人"
|
||||
clearable
|
||||
filterable
|
||||
class="full-control"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editOperatorOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="editForm.remark"
|
||||
@@ -299,6 +512,91 @@ async function handleDelete(row: ManualEntryItem) {
|
||||
<el-button type="primary" :loading="editSubmitting" @click="handleUpdate">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 平台 / 操作人配置弹窗 -->
|
||||
<el-dialog
|
||||
v-model="configVisible"
|
||||
title="配置平台与操作人"
|
||||
width="720px"
|
||||
destroy-on-close
|
||||
class="manual-entry-config-dialog"
|
||||
>
|
||||
<p class="option-config-tip">
|
||||
这里维护的可选项会出现在录单表单的下拉中;删除选项不会影响已登记的历史记录。
|
||||
</p>
|
||||
<div class="option-config-grid">
|
||||
<section class="option-config-panel">
|
||||
<header class="option-config-title">平台</header>
|
||||
<div class="option-config-add">
|
||||
<el-input
|
||||
v-model="newPlatformName"
|
||||
placeholder="新增平台名称"
|
||||
maxlength="64"
|
||||
clearable
|
||||
@keyup.enter="handleAddOption('platform')"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="optionSubmitting"
|
||||
@click="handleAddOption('platform')"
|
||||
>
|
||||
添加
|
||||
</el-button>
|
||||
</div>
|
||||
<ul class="option-config-list">
|
||||
<li v-for="item in options.platforms" :key="item.id">
|
||||
<span class="option-config-name">{{ item.name }}</span>
|
||||
<span class="option-config-actions">
|
||||
<el-button link type="primary" size="small" @click="handleRenameOption(item)">
|
||||
重命名
|
||||
</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleRemoveOption(item)">
|
||||
删除
|
||||
</el-button>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-if="!options.platforms.length" class="option-config-empty">暂无平台,请先添加</p>
|
||||
</section>
|
||||
|
||||
<section class="option-config-panel">
|
||||
<header class="option-config-title">操作人</header>
|
||||
<div class="option-config-add">
|
||||
<el-input
|
||||
v-model="newOperatorName"
|
||||
placeholder="新增操作人名称"
|
||||
maxlength="64"
|
||||
clearable
|
||||
@keyup.enter="handleAddOption('operator')"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="optionSubmitting"
|
||||
@click="handleAddOption('operator')"
|
||||
>
|
||||
添加
|
||||
</el-button>
|
||||
</div>
|
||||
<ul class="option-config-list">
|
||||
<li v-for="item in options.operators" :key="item.id">
|
||||
<span class="option-config-name">{{ item.name }}</span>
|
||||
<span class="option-config-actions">
|
||||
<el-button link type="primary" size="small" @click="handleRenameOption(item)">
|
||||
重命名
|
||||
</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleRemoveOption(item)">
|
||||
删除
|
||||
</el-button>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-if="!options.operators.length" class="option-config-empty">暂无操作人,请先添加</p>
|
||||
</section>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="configVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user