修复已知问题

This commit is contained in:
2026-02-26 16:29:19 +08:00
parent f7f0c945ec
commit 37901c9847
10 changed files with 369 additions and 551 deletions

View File

@@ -1,3 +1,6 @@
{
"recommendations": ["Vue.volar"]
"recommendations": [
"Vue.volar",
"google.geminicodeassist"
]
}

View File

@@ -1,8 +1,14 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
"@/*": [
"./src/*"
]
}
},
"exclude": ["node_modules", "dist"]
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -1,194 +0,0 @@
<template>
<el-dialog v-model="dialogVisible" :title="isEditing ? '📝 编辑工单任务' : '✨ 创建新工单'" width="550px" class="modern-dialog"
destroy-on-close @close="handleClose">
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="compact-form">
<div class="form-section">
<div class="section-title">业务基础信息</div>
<el-form-item label="网站地址" prop="website">
<el-input v-model="form.website" placeholder="请输入网站 URL" clearable>
<template #prefix>
<el-icon><Link /></el-icon>
</template>
</el-input>
</el-form-item>
</div>
<div class="form-section people-grid">
<div class="section-title column-full">权责分配</div>
<el-form-item label="客户单位 (外方)" prop="customer_id" class="client-item">
<el-select v-model="current_customer_id" placeholder="请选择单位" style="width: 100%" filterable @change="handleCustomerChange">
<el-option
v-for="item in customers"
:key="item.customer_id"
:label="item.company_name"
:value="item.customer_id"
/>
</el-select>
</el-form-item>
<el-form-item label="运营人员 (外方)" prop="operator" class="client-item">
<el-select
v-model="form.operator"
placeholder="请选择人员"
style="width: 100%"
filterable
:disabled="!current_customer_id"
>
<el-option
v-for="item in filteredEmployees"
:key="item.employee_id"
:label="item.employee_name"
:value="item.employee_name"
/>
</el-select>
</el-form-item>
<el-form-item label="负责人 (我方)" prop="staff_id" class="owner-item column-full">
<el-select v-model="form.staff_id" placeholder="请选择我方负责人" style="width: 100%" filterable>
<el-option
v-for="item in staffs"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</div>
<div class="form-section">
<el-form-item label="当前进度">
<el-radio-group v-model="form.is_complete" class="modern-radio-group">
<el-radio-button label="未分配">未分配</el-radio-button>
<el-radio-button label="进行中">进行中</el-radio-button>
<el-radio-button label="已完成">已完成</el-radio-button>
<el-radio-button label="已完结">已完结</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备注说明" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="填写相关的补充信息或注意事项..." resize="none" />
</el-form-item>
</div>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false" plain>取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitting" class="submit-btn">
{{ isEditing ? '保存修改' : '立即创建' }}
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, watch, computed, nextTick } from 'vue'
import { Link } from '@element-plus/icons-vue'
const emit = defineEmits(['update:modelValue', 'submit'])
const props = defineProps({
modelValue: Boolean,
formData: Object,
customers: Array, // 外部客户单位列表
customerEmployees: Array, // 外部客户员工列表
staffs: Array, // 我方员工列表
isEditing: Boolean
})
const dialogVisible = ref(false)
const formRef = ref()
const submitting = ref(false)
const current_customer_id = ref(null) // 级联用的中间变量
const form = reactive({
website: '',
operator: '',
staff_id: null,
is_complete: "未分配",
remark: ''
})
const rules = {
website: [{ required: true, message: '请输入网站地址', trigger: 'blur' }],
operator: [{ required: true, message: '请选择运营人员', trigger: 'change' }],
staff_id: [{ required: true, message: '请选择负责人', trigger: 'change' }]
}
// 核心逻辑:级联过滤
const filteredEmployees = computed(() => {
if (!current_customer_id.value) return []
return props.customerEmployees.filter(emp => emp.customer_id === current_customer_id.value)
})
// 单位切换时清空人员
const handleCustomerChange = () => {
form.operator = ''
}
// 监听弹窗显隐与数据回显
watch(() => props.modelValue, (val) => {
dialogVisible.value = val
if (val) {
nextTick(() => {
resetForm()
if (props.isEditing && props.formData) {
Object.assign(form, props.formData)
// 回显逻辑:根据 operator 姓名反查所属 customer_id
const employee = props.customerEmployees.find(e => e.employee_name === props.formData.operator)
if (employee) {
current_customer_id.value = employee.customer_id
}
}
})
}
})
watch(() => dialogVisible.value, (val) => emit('update:modelValue', val))
const resetForm = () => {
if (formRef.value) formRef.value.resetFields()
current_customer_id.value = null
Object.assign(form, {
website: '',
operator: '',
staff_id: null,
is_complete: "未分配",
remark: ''
})
}
const handleClose = () => resetForm()
const handleSubmit = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
submitting.value = true
emit('submit', { ...form })
} catch (e) {
console.log('表单校验失败')
} finally {
submitting.value = false
}
}
</script>
<style scoped>
:deep(.modern-dialog) { border-radius: 12px; overflow: hidden; }
.form-section { margin-bottom: 24px; }
.section-title { font-size: 14px; font-weight: 600; color: #1e293b; margin-bottom: 12px; display: flex; align-items: center; }
.section-title::before { content: ""; width: 4px; height: 14px; background: #409eff; margin-right: 8px; border-radius: 2px; }
.people-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.column-full { grid-column: span 2; }
:deep(.client-item .el-form-item__label) { color: #909399 !important; }
:deep(.owner-item .el-form-item__label) { color: #409eff !important; }
.modern-radio-group { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); border-radius: 8px; overflow: hidden; }
.dialog-footer { padding-top: 10px; }
.submit-btn { padding-left: 24px; padding-right: 24px; font-weight: 600; }
:deep(.el-form-item) { margin-bottom: 18px; }
:deep(.el-form-item__label) { padding-bottom: 4px !important; font-size: 13px; }
</style>

View File

@@ -4,7 +4,11 @@
<div class="search-container">
<div class="filter-main">
<el-form-item label="工单状态">
<el-radio-group v-model="localFilters.status" size="default" @change="handleSearch">
<el-radio-group
v-model="localFilters.status"
size="default"
@change="handleSearch"
>
<el-radio-button :label="null">全部</el-radio-button>
<el-radio-button :label="0">未分配</el-radio-button>
<el-radio-button :label="1">进行中</el-radio-button>
@@ -69,7 +73,12 @@
</div>
<div class="filter-actions">
<el-button type="primary" :icon="Search" @click="handleSearch" class="search-btn">
<el-button
type="primary"
:icon="Search"
@click="handleSearch"
class="search-btn"
>
执行筛选
</el-button>
<el-button @click="$emit('reset')" plain>重置条件</el-button>
@@ -78,8 +87,12 @@
<el-button icon="Sort">排序</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="setSort('desc')">创建时间 (新→旧)</el-dropdown-item>
<el-dropdown-item @click="setSort('asc')">创建时间 (旧→新)</el-dropdown-item>
<el-dropdown-item @click="setSort('desc')"
>创建时间 (新→旧)</el-dropdown-item
>
<el-dropdown-item @click="setSort('asc')"
>创建时间 (旧→新)</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -90,48 +103,48 @@
</template>
<script setup>
import { reactive, watch } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { reactive, watch } from "vue";
import { Search } from "@element-plus/icons-vue";
const props = defineProps({
filters: {
type: Object,
required: true
required: true,
},
// 传入的是所有客户员工的名字数组 [ "张三", "李四", ... ]
operators: {
type: Array,
default: () => []
default: () => [],
},
// 传入的是我方员工对象数组 [ {id: 1, name: "管理员"}, ... ]
staffs: {
type: Array,
default: () => []
}
})
default: () => [],
},
});
const emit = defineEmits(['filter-change', 'reset'])
const emit = defineEmits(["filter-change", "reset"]);
// 本地副本
const localFilters = reactive({ ...props.filters })
const localFilters = reactive({ ...props.filters });
// 深度监听父组件 filters,用于同步重置状态
watch(
() => props.filters,
(newFilters) => {
Object.assign(localFilters, newFilters)
Object.assign(localFilters, newFilters);
},
{ deep: true }
)
);
const handleSearch = () => {
emit('filter-change', { ...localFilters })
}
emit("filter-change", { ...localFilters });
};
const setSort = (order) => {
localFilters.sort_order = order
handleSearch()
}
localFilters.sort_order = order;
handleSearch();
};
</script>
<style scoped>
@@ -165,17 +178,38 @@ const setSort = (order) => {
gap: 16px;
align-items: center;
}
.w-150 { width: 160px; }
.search-input { width: 280px; }
.divider { margin: 0 4px; color: #dcdfe6; }
.filter-actions { display: flex; gap: 10px; padding-top: 4px; }
.search-btn { padding: 12px 24px; font-weight: bold; letter-spacing: 1px; }
.w-150 {
width: 160px;
}
.search-input {
width: 280px;
}
.divider {
margin: 0 4px;
color: #dcdfe6;
}
.filter-actions {
display: flex;
gap: 10px;
padding-top: 4px;
}
.search-btn {
padding: 12px 24px;
font-weight: bold;
letter-spacing: 1px;
}
@media (max-width: 1024px) {
.search-input { width: 200px; }
.search-input {
width: 200px;
}
}
@media (max-width: 768px) {
.search-container { flex-direction: column; }
.search-input { width: 100%; }
.search-container {
flex-direction: column;
}
.search-input {
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,262 @@
<template>
<el-dialog v-model="dialogVisible" :title="isEditing ? '📝 编辑工单任务' : '✨ 创建新工单'" width="550px" class="modern-dialog"
destroy-on-close @close="handleClose">
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="compact-form">
<div class="form-section">
<div class="section-title">业务基础信息</div>
<el-form-item label="网站地址" prop="website">
<el-input v-model="form.website" placeholder="请输入网站 URL" clearable>
<template #prefix>
<el-icon>
<Link />
</el-icon>
</template>
</el-input>
</el-form-item>
</div>
<div class="form-section people-grid">
<div class="section-title column-full">权责分配</div>
<el-form-item label="客户单位 (外方)" prop="customer_id" class="client-item">
<el-select v-model="current_customer_id" placeholder="请选择单位" style="width: 100%" filterable
@change="handleCustomerChange">
<el-option v-for="item in customers" :key="item.customer_id" :label="item.company_name"
:value="item.customer_id" />
</el-select>
</el-form-item>
<el-form-item label="运营人员 (外方)" prop="operator" class="client-item">
<el-select v-model="form.operator" placeholder="请选择人员" style="width: 100%" filterable
:disabled="!current_customer_id">
<el-option v-for="item in filteredEmployees" :key="item.employee_id" :label="item.employee_name"
:value="item.employee_name" />
</el-select>
</el-form-item>
<el-form-item v-if="isEditing" label="负责人 (我方)" prop="staff_id" class="owner-item column-full">
<el-select v-model="form.staff_id" placeholder="请选择我方负责人" style="width: 100%" filterable>
<el-option v-for="item in staffs" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</div>
<div class="form-section">
<el-form-item label="当前进度">
<el-radio-group v-model="form.is_complete" class="modern-radio-group">
<el-radio-button label="未分配">未分配</el-radio-button>
<el-radio-button label="进行中">进行中</el-radio-button>
<el-radio-button label="已完成">已完成</el-radio-button>
<el-radio-button label="已完结">已完结</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备注说明" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="填写相关的补充信息或注意事项..." resize="none" />
</el-form-item>
</div>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false" plain>取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitting" class="submit-btn">
{{ isEditing ? "保存修改" : "立即创建" }}
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, watch, computed, nextTick } from "vue";
import { Link } from "@element-plus/icons-vue";
const emit = defineEmits(["update:modelValue", "submit"]);
const props = defineProps({
modelValue: Boolean,
formData: Object,
customers: Array, // 外部客户单位列表
customerEmployees: Array, // 外部客户员工列表
staffs: Array, // 我方员工列表
isEditing: Boolean,
});
const dialogVisible = ref(false);
const formRef = ref();
const submitting = ref(false);
const current_customer_id = ref(null); // 级联用的中间变量
const form = reactive({
website: "",
operator: "",
staff_id: null,
is_complete: "未分配",
remark: "",
});
// 使用 computed 动态切换校验逻辑
const rules = computed(() => {
const baseRules = {
website: [{ required: true, message: "请输入网站地址", trigger: "blur" }],
operator: [{ required: true, message: "请选择运营人员", trigger: "change" }],
};
// 仅在编辑模式下,将 staff_id 设为必填
if (props.isEditing) {
baseRules.staff_id = [{ required: true, message: "请选择负责人", trigger: "change" }];
}
return baseRules;
});
// 核心逻辑:级联过滤
const filteredEmployees = computed(() => {
if (!current_customer_id.value) return [];
return props.customerEmployees.filter(
(emp) => emp.customer_id === current_customer_id.value
);
});
// 单位切换时清空人员
const handleCustomerChange = () => {
form.operator = "";
};
// 监听弹窗显隐与数据回显
watch(
() => props.modelValue,
(val) => {
dialogVisible.value = val;
if (val) {
nextTick(() => {
resetForm();
if (props.isEditing && props.formData) {
Object.assign(form, props.formData);
// 回显逻辑:根据 operator 姓名反查所属 customer_id
const employee = props.customerEmployees.find(
(e) => e.employee_name === props.formData.operator
);
if (employee) {
current_customer_id.value = employee.customer_id;
}
}
});
}
}
);
watch(
() => dialogVisible.value,
(val) => emit("update:modelValue", val)
);
const resetForm = () => {
if (formRef.value) formRef.value.resetFields();
current_customer_id.value = null;
Object.assign(form, {
website: "",
operator: "",
staff_id: null,
is_complete: "未分配",
remark: "",
});
};
const handleClose = () => resetForm();
const handleSubmit = async () => {
if (!formRef.value) return;
try {
await formRef.value.validate();
submitting.value = true;
// 复制一份表单数据进行处理
const submitData = { ...form };
// 如果是新增模式,强制将 staff_id 设为 null
if (!props.isEditing) {
submitData.staff_id = null;
}
emit("submit", submitData);
} catch (e) {
console.log("表单校验失败", e);
} finally {
submitting.value = false;
}
};
</script>
<style scoped>
:deep(.modern-dialog) {
border-radius: 12px;
overflow: hidden;
}
.form-section {
margin-bottom: 24px;
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #1e293b;
margin-bottom: 12px;
display: flex;
align-items: center;
}
.section-title::before {
content: "";
width: 4px;
height: 14px;
background: #409eff;
margin-right: 8px;
border-radius: 2px;
}
.people-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.column-full {
grid-column: span 2;
}
:deep(.client-item .el-form-item__label) {
color: #909399 !important;
}
:deep(.owner-item .el-form-item__label) {
color: #409eff !important;
}
.modern-radio-group {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
border-radius: 8px;
overflow: hidden;
}
.dialog-footer {
padding-top: 10px;
}
.submit-btn {
padding-left: 24px;
padding-right: 24px;
font-weight: 600;
}
:deep(.el-form-item) {
margin-bottom: 18px;
}
:deep(.el-form-item__label) {
padding-bottom: 4px !important;
font-size: 13px;
}
</style>

View File

@@ -24,7 +24,7 @@ const router = createRouter({
{
path: 'customers',
name: 'customers',
component: () => import('../views/CustomersView.vue'),
component: () => import('../views/CustomersManagement.vue'),
meta: { requiresAuth: true, role: 'admin' }
},
]

View File

@@ -1,289 +0,0 @@
<template>
<div class="customers-container">
<h2>客户及员工管理系统</h2>
<div class="action-bar">
<div class="search-group">
<el-input v-model="searchQuery" placeholder="搜索客户单位" style="width: 250px" clearable />
</div>
<div class="button-group">
<el-button type="primary" :icon="Plus" @click="handleAddCustomer">新增客户单位</el-button>
<el-button type="success" :icon="User" @click="handleAddEmployee">新增员工</el-button>
</div>
</div>
<el-table :data="filteredData" border style="width: 100%; margin-top: 20px" v-loading="loading">
<el-table-column prop="customer_id" label="客户ID" width="100" />
<el-table-column prop="company_name" label="客户单位名称" />
<el-table-column label="员工管理" width="250" align="center">
<template #default="scope">
<span style="margin-right: 15px">
共 <b style="color: #409EFF">{{ getEmployeeCount(scope.row.customer_id) }}</b> 人
</span>
<el-button
size="small"
type="primary"
link
:icon="View"
@click="showEmployeeDetails(scope.row)"
>查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button size="small" type="danger" plain @click="handleDeleteCustomer(scope.row)">删除单位</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="customerDialogVisible" title="新增客户单位" width="400px">
<el-form :model="customerForm" label-width="100px">
<el-form-item label="单位名称" required>
<el-input v-model="customerForm.company_name" placeholder="例如:方舟星河" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="customerDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitCustomer">确定</el-button>
</template>
</el-dialog>
<el-dialog v-model="employeeDialogVisible" title="新增客户员工" width="450px">
<el-form :model="employeeForm" label-width="100px">
<el-form-item label="员工姓名" required>
<el-input v-model="employeeForm.employee_name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="所属客户" required>
<el-select v-model="employeeForm.customer_id" placeholder="请选择归属单位" style="width: 100%">
<el-option
v-for="item in customerList"
:key="item.customer_id"
:label="item.company_name"
:value="item.customer_id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="employeeDialogVisible = false">取消</el-button>
<el-button type="success" @click="submitEmployee">保存员工</el-button>
</template>
</el-dialog>
<el-dialog v-model="employeeDetailVisible" :title="`【${activeCustomerName}】员工名单`" width="500px">
<el-table :data="currentCustomerEmployees" border stripe>
<el-table-column prop="employee_id" label="员工ID" width="100" />
<el-table-column prop="employee_name" label="姓名" />
<el-table-column label="操作" width="100" align="center">
<template #default="scope">
<el-button
size="small"
type="danger"
link
@click="confirmDeleteEmployee(scope.row.employee_id)"
>移除</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { Plus, User, View } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { customerApi } from '@/api/ticket' // 确保路径指向包含 addCustomerName 的 API 文件
// --- 状态数据 ---
const loading = ref(false)
const customerList = ref([])
const employeeList = ref([])
const searchQuery = ref('')
const employeeDetailVisible = ref(false)
const activeCustomerName = ref('')
const activeCustomerId = ref(null)
// --- 表单数据 ---
const customerDialogVisible = ref(false)
const customerForm = ref({ company_name: '' })
const employeeDialogVisible = ref(false)
const employeeForm = ref({ employee_name: '', customer_id: null })
// --- 核心方法 ---
// 1. 获取全局数据
const fetchCustomers = async () => {
loading.value = true
try {
const res = await customerApi.getCustomers()
if (res.code === 200) {
customerList.value = res.customers || []
employeeList.value = res.employees || []
} else {
ElMessage.error(res.msg || '数据加载失败')
}
} catch (error) {
console.error('API Error:', error)
ElMessage.error('无法连接到服务器')
} finally {
loading.value = false
}
}
// 2. 统计处理
const getEmployeeCount = (id) => {
return employeeList.value.filter(emp => emp.customer_id === id).length
}
const currentCustomerEmployees = computed(() => {
return employeeList.value.filter(emp => emp.customer_id === activeCustomerId.value)
})
const filteredData = computed(() => {
return customerList.value.filter(item =>
item.company_name.toLowerCase().includes(searchQuery.value.toLowerCase())
)
})
// 3. 客户管理逻辑
const handleAddCustomer = () => {
customerForm.value.company_name = ''
customerDialogVisible.value = true
}
const submitCustomer = async () => {
if (!customerForm.value.company_name) return ElMessage.error('名称不能为空')
try {
const res = await customerApi.addCustomerName({
company_name: customerForm.value.company_name
})
console.log('返回数据',res)
if (res.code === 200) {
ElMessage.success('客户单位创建成功')
customerDialogVisible.value = false
fetchCustomers()
}
} catch (error) {
ElMessage.error('创建失败')
}
}
const handleDeleteCustomer = (row) => {
ElMessageBox.confirm(
`确定删除单位【${row.company_name}】吗?这将同时移除该单位下所有员工,操作不可恢复!`,
'极其危险的操作',
{
confirmButtonText: '确定彻底删除',
cancelButtonText: '取消',
type: 'error',
// 让确定按钮看起来更显眼(红色)
confirmButtonClass: 'el-button--danger',
}
).then(async () => {
// 1. 开启全局或表格的 loading 状态(如果有的话)
loading.value = true;
try {
// 2. 调用接口,注意参数要包装成对象,匹配后端 $this->request->param('customer_id')
const res = await customerApi.deleteCustomer(row.customer_id);
// 3. 根据返回结果进行反馈
if (res.code === 200) {
ElMessage.success({
message: `单位【${row.company_name}】及其员工已成功清理`,
showClose: true
});
// 4. 刷新列表数据
await fetchCustomers();
} else {
ElMessage.error(res.msg || '删除失败,请联系管理员');
}
} catch (error) {
console.error('删除客户出错:', error);
ElMessage.error('网络连接超时或服务器异常');
} finally {
// 5. 无论成功失败都关闭 loading
loading.value = false;
}
}).catch(() => {
// 用户点击取消,无需处理
console.log('用户取消删除');
});
};
// 4. 员工管理逻辑
const handleAddEmployee = () => {
if (customerList.value.length === 0) return ElMessage.warning('请先创建客户单位')
employeeForm.value = { employee_name: '', customer_id: null }
employeeDialogVisible.value = true
}
const submitEmployee = async () => {
if (!employeeForm.value.employee_name || !employeeForm.value.customer_id) {
return ElMessage.error('请填写员工姓名并选择所属单位')
}
try {
// console.log('这个是姓名',employeeForm.value.employee_name)
// 注意:确保你的 api 文件中有 addEmployee 方法
const res = await customerApi.addEmployee({
emp_name: employeeForm.value.employee_name,
customer_id: employeeForm.value.customer_id
})
if (res.code === 200) {
ElMessage.success('员工保存成功')
employeeDialogVisible.value = false
fetchCustomers()
}
} catch (error) {
ElMessage.error('保存失败')
}
}
const showEmployeeDetails = (row) => {
activeCustomerId.value = row.customer_id
activeCustomerName.value = row.company_name
employeeDetailVisible.value = true
}
//删除所属员工
const confirmDeleteEmployee = (empId) => {
ElMessageBox.confirm('确定要从该单位移除此员工吗?', '提示', { type: 'warning' }).then(async () => {
try {
// console.log('删除员工的ID',empId);
const res = await customerApi.deleteEmployee(empId) // 后端删除员工接口
if (res.code == 200 || res.code == true){
ElMessage.success('操作成功')
employeeDetailVisible.value = false;
fetchCustomers();
}
} catch (e) {
ElMessage.error('删除失败')
}
}).catch(() => {})
}
onMounted(() => {
fetchCustomers()
})
</script>
<style scoped>
.customers-container { padding: 30px; background-color: #f5f7fa; min-height: 100vh; }
h2 { margin-bottom: 25px; color: #303133; font-weight: 600; }
.action-bar {
display: flex;
justify-content: space-between;
background: #fff;
padding: 15px 20px;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.05);
}
.button-group .el-button { margin-left: 10px; }
:deep(.el-table__header) { color: #606266; font-weight: bold; }
</style>

View File

@@ -93,9 +93,9 @@ import { Plus, Memo, Clock, Loading, CircleCheck, Checked } from '@element-plus/
import { ticketApi ,customerApi} from '@/api/ticket'
// 组件引入
import TicketFilter from '@/components/TicketFilter.vue'
import TicketList from '@/components/TicketList.vue'
import TicketForm from '@/components/TicketForm.vue'
import TicketFilter from '@/components/ticket/TicketFilter.vue'
import TicketList from '@/components/ticket/TicketList.vue'
import TicketForm from '@/components/ticket/TicketForm.vue'
// --- 响应式状态 ---
const tickets = ref([])

View File

@@ -25,8 +25,4 @@ export default defineConfig({
}
}
}
})