Commit a6c634b7 by 李宁

自己测试完成

1 parent 723d1ec0
......@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title>商机办结登记</title>
</head>
<body>
<div id="app"></div>
......
......@@ -207,7 +207,7 @@
</div>
<template #footer>
<el-button type="primary" @click="submitExcelData">{{uploadResult.failed>0?'确定':'提交'}}</el-button>
<el-button type="primary" @click="submitExcelData">{{(uploadResult?.failed || 0)>0?'确定':'提交'}}</el-button>
</template>
</el-dialog>
</div>
......@@ -445,7 +445,7 @@ const handleFileChange = async (e: Event) => {
}
const submitExcelData = async ()=>{
if(uploadResult.value.failed > 0){
if((uploadResult.value?.failed || 0) > 0){
showUploadResult.value = false
return
}
......@@ -466,7 +466,7 @@ const submitExcelData = async ()=>{
}
}
const excelShowdData = ref([])
const excelShowdData = ref<any[]>([])
const processUploadData = (data: any[]) => {
const errors: string[] = []
let successCount = 0
......@@ -474,7 +474,7 @@ const processUploadData = (data: any[]) => {
excelShowdData.value = data
// 获取现有的业务代码集合
const existingCodes = new Set(props.rules.map(r => r.businessCode.toLowerCase()))
const existingCodes = new Set(props.rules.map((r: any) => r.businessCode?.toLowerCase?.() || ''))
data.forEach((row, index) => {
const rowNum = index + 3 // Excel行号(从1开始,跳过表头)
......
......@@ -192,9 +192,9 @@
>
<div class="text-left">
<p class="text-sm text-neutral-900 text-[14px] font-bold">{{ currentUser?.username || '管理员' }}</p>
<p class="text-xs text-neutral-500">
<!-- <p class="text-xs text-neutral-500">
{{ currentUser?.role === 'admin' ? '系统管理员' : '普通用户' }}
</p>
</p> -->
</div>
<ChevronDown :size="16" class="text-neutral-400" />
</el-button>
......@@ -235,9 +235,9 @@
<!-- 业务酬金管理页面 -->
<BusinessRulesManagement
v-else-if="activeView === 'business'"
:rules="businessRules"
@add="handleAddBusinessRule"
@update="handleUpdateBusinessRule"
:rules="businessRules as any"
@add="handleAddBusinessRule as any"
@update="handleUpdateBusinessRule as any"
@toggle-status="handleToggleBusinessRuleStatus"
@delete="handleDeleteBusinessRule"
/>
......@@ -245,7 +245,7 @@
<!-- 角色管理页面 -->
<RoleManagement
v-else-if="activeView === 'roles'"
:roles="roles"
:roles="roles as any"
:permissions="permissions"
@add-role="handleAddRole"
@update-role="handleUpdateRole"
......@@ -297,12 +297,14 @@ const platformLogo = ref(platformLogoImg)
const { $api } = getCurrentInstance()!.appContext.config.globalProperties
// 本地Role类型定义,确保permissions字段是必需的
interface Role {
id: number
id: string
roleName: string
status: 1 | 0
name: string
level: '地市级' | '区县级' | '一线人员'
status: '启用' | '禁用'
remark?: string
permissionIds?: string[]
permissions?: string[]
permissions: string[]
createTime?: string
}
interface DesktopMainProps {
......@@ -315,7 +317,7 @@ const isSidebarCollapsed = ref(false)
const activeMenu = ref<string>('orders') // 当前激活的菜单
const activeView = ref<string>('orders') // 当前显示的视图
const selectedOrderId = ref<string | null>(null) // 当前查看的订单ID
const selectedOrder = ref<{}>(null) // 当前查看的订单ID
const selectedOrder = ref<any>(null) // 当前查看的订单
const userInfo = ref(localStorage.getItem('pcUserInfo') ? JSON.parse(localStorage.getItem('pcUserInfo') as string) : {})
// 菜单配置
// const businessMenuItems = [
......@@ -386,6 +388,10 @@ const businessRules = ref<BusinessRule[]>([
businessName: '5G套餐办理',
estimatedReward: 50,
status: '生效中',
jobName: '5G套餐办理',
jobId: 'JOB001',
preMoney: 50,
totalPrice: 50,
createTime: '2025-10-20 10:00'
},
{
......@@ -394,6 +400,10 @@ const businessRules = ref<BusinessRule[]>([
businessName: '宽带新装',
estimatedReward: 80,
status: '生效中',
jobName: '宽带新装',
jobId: 'JOB002',
preMoney: 80,
totalPrice: 80,
createTime: '2025-10-20 10:05'
},
{
......@@ -402,6 +412,10 @@ const businessRules = ref<BusinessRule[]>([
businessName: '话费充值',
estimatedReward: 30,
status: '生效中',
jobName: '话费充值',
jobId: 'JOB003',
preMoney: 30,
totalPrice: 30,
createTime: '2025-10-20 10:10'
},
{
......@@ -410,6 +424,10 @@ const businessRules = ref<BusinessRule[]>([
businessName: '流量包办理',
estimatedReward: 40,
status: '已停用',
jobName: '流量包办理',
jobId: 'JOB004',
preMoney: 40,
totalPrice: 40,
createTime: '2025-10-20 10:15'
}
])
......@@ -426,6 +444,10 @@ interface BusinessRule {
estimatedReward: number
status: "生效中" | "已停用"
createTime: string
jobName: string
preMoney: number
jobId: string
totalPrice: number
}
interface Organization {
id: string
......@@ -537,7 +559,10 @@ const handleToggleBusinessRuleStatus = (ruleId: string) => {
if (rule) {
const currentStatus = rule.status
const newStatus = currentStatus === '生效中' ? '已停用' : '生效中'
rule.status = newStatus
businessRules.value[ruleIndex] = {
...rule,
status: newStatus
}
ElMessage.success(`业务规则已${newStatus === '生效中' ? '启用' : '停用'}`)
console.log('切换业务规则状态:', ruleId, newStatus)
}
......@@ -554,12 +579,12 @@ const handleDeleteBusinessRule = (ruleId: string) => {
// 角色管理方法
const handleAddRole = (roleData: any) => {
const newRole: Role = {
id: Date.now(),
id: String(Date.now()),
roleName: roleData.roleName || roleData.name || '',
name: roleData.name || roleData.roleName,
level: roleData.level,
description: roleData.description,
permissions: roleData.permissions || roleData.permissionIds || [],
status: 1,
status: '启用',
createTime: new Date().toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
......@@ -572,8 +597,8 @@ const handleAddRole = (roleData: any) => {
roles.value.push(newRole)
console.log('新增角色:', newRole)
}
const handleUpdateRole = (roleId: number, updates: any) => {
const roleIndex = roles.value.findIndex(role => role.id === roleId)
const handleUpdateRole = (roleId: string, updates: any) => {
const roleIndex = roles.value.findIndex((role: any) => String(role.id) === roleId)
if (roleIndex !== -1) {
const existingRole = roles.value[roleIndex]
if (existingRole) {
......
......@@ -347,6 +347,8 @@ interface Order {
chinaPersonName: string
customerPhone: string
job: string
jobName?: string
memo?: string
createTime: string
status: status
auditStatus?: auditStatus
......@@ -398,7 +400,7 @@ onMounted(()=>{
queryLog()
})
const logData = ref([])
const logData = ref<any[]>([])
const queryLog = async ()=>{
try {
const response = await $api.queryOrderLog({
......@@ -406,7 +408,7 @@ const queryLog = async ()=>{
})
if (response.c === 0) {
response.d.forEach(item=>{
response.d.forEach((item: any)=>{
item.detail = JSON.parse(item.parameter)
})
......
......@@ -476,10 +476,10 @@
<el-button @click="closeBatchDialog">取消</el-button>
<el-button
type="primary"
:disabled="!batchParseDone || batchValidRows.length === 0"
:disabled="!batchParseDone || batchInvalidRows.length>0"
@click="openVerifyDialog"
>
提交审核{{ batchValidRows.length }}
提交审核
</el-button>
</template>
</el-dialog>
......@@ -603,8 +603,8 @@ const verifyCode = ref('')
const orders = ref<any[]>([])
// 类型定义
type BusinessStatus = '待办理' | '办理成功' | '已关闭'
type ReviewStatus = '待审核' | '审核通过' | '审核驳回'
type BusinessStatus = '待办理' | '办理成功' | '已关闭' | '-1' | '0' | '1'
type ReviewStatus = '待审核' | '审核通过' | '审核驳回' | '0' | '1' | '2'
interface OperationLog {
id: string
......@@ -635,201 +635,55 @@ interface Order {
operationLogs?: OperationLog[]
}
// 生成模拟数据
const generateMockOrders = (): Order[] => {
const mockOrders: Order[] = []
const names = [
'王芳', '李静', '刘备', '关羽', '张飞', '赵云', '马超', '黄忠', '魏延', '姜维',
'陈明', '李娜', '王强', '赵丽', '孙杰', '周芳', '吴军', '郑敏', '刘洋', '黄涛',
'杨雪', '朱鹏', '徐霞', '何亮', '高华', '林静', '梁伟', '宋佳', '韩冰', '唐磊',
'冯琳', '许刚', '曹丽', '蔡勇', '彭燕', '马强', '卢敏', '陆伟', '姚娟', '钱浩',
'秦霞', '任杰', '沈芳', '汤明', '田丽', '万强', '温娜', '夏伟', '谢静', '熊勇'
]
const businesses = ['5G套餐办理', '宽带新装', '话费充值', '流量包办理']
const businessRewards = { '5G套餐办理': 50, '宽带新装': 80, '话费充值': 30, '流量包办理': 40 }
const businessStatuses: BusinessStatus[] = ['待办理', '办理成功', '已关闭']
const reviewStatuses: ReviewStatus[] = ['待审核', '审核通过', '审核驳回']
for (let i = 0; i < 120; i++) {
const dayOffset = Math.floor(i / 10)
const date = new Date(2025, 9, 28 - dayOffset)
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
const orderId = `ORD${dateStr.replace(/-/g, '')}${String(i + 1).padStart(3, '0')}`
const name = names[i % names.length] as string
const phone = `138${String(10000 + i).padStart(8, '0')}`
const customerPhone = `139${String(20000 + i).padStart(8, '0')}`
const businessName = businesses[i % businesses.length] as string
const estimatedReward = businessRewards[businessName as keyof typeof businessRewards]
// 根据索引分配不同的状态
const statusType = i % 6
let businessStatus: BusinessStatus
let reviewStatus: ReviewStatus | undefined
let actualReward: number | undefined
let crmOrderNumber: string | undefined
let completeTime: string | undefined
let paymentTime: string | undefined
let rejectReason: string | undefined
let closeReason: string | undefined
const operationLogs: OperationLog[] = []
if (statusType === 0) {
// 待办理 (约17%)
businessStatus = '待办理'
} else if (statusType === 1) {
// 办理成功+待审核 (约17%)
businessStatus = '办理成功'
reviewStatus = '待审核'
actualReward = estimatedReward + (Math.random() > 0.5 ? Math.floor(Math.random() * 10) : -Math.floor(Math.random() * 5))
crmOrderNumber = `CRM${dateStr.replace(/-/g, '')}${String(i + 1000).padStart(4, '0')}`
completeTime = `${dateStr} ${String(14 + (i % 8)).padStart(2, '0')}:${String((i * 7) % 60).padStart(2, '0')}`
} else if (statusType === 2) {
// 办理成功+审核通过 (约17%)
businessStatus = '办理成功'
reviewStatus = '审核通过'
actualReward = estimatedReward + (Math.random() > 0.7 ? Math.floor(Math.random() * 5) : 0)
crmOrderNumber = `CRM${dateStr.replace(/-/g, '')}${String(i + 1000).padStart(4, '0')}`
completeTime = `${dateStr} ${String(14 + (i % 8)).padStart(2, '0')}:${String((i * 7) % 60).padStart(2, '0')}`
paymentTime = `${dateStr} ${String(16 + (i % 6)).padStart(2, '0')}:${String((i * 17) % 60).padStart(2, '0')}`
} else if (statusType === 3) {
// 办理成功+审核驳回 (约17%)
businessStatus = '办理成功'
reviewStatus = '审核驳回'
actualReward = estimatedReward + (i % 3 === 0 ? 25 : i % 3 === 1 ? -15 : 10)
crmOrderNumber = `CRM${dateStr.replace(/-/g, '')}${String(i + 1000).padStart(4, '0')}`
completeTime = `${dateStr} ${String(14 + (i % 8)).padStart(2, '0')}:${String((i * 7) % 60).padStart(2, '0')}`
rejectReason = ['金额与实际不符', 'CRM订单号有误', '缺少必要凭证', '客户信息不匹配'][i % 4]
} else if (statusType === 4) {
// 已关闭 (约17%)
businessStatus = '已关闭'
actualReward = estimatedReward
crmOrderNumber = `CRM${dateStr.replace(/-/g, '')}${String(i + 1000).padStart(4, '0')}`
completeTime = `${dateStr} ${String(14 + (i % 8)).padStart(2, '0')}:${String((i * 7) % 60).padStart(2, '0')}`
closeReason = ['客户取消办理', '业务规则变更', '重复订单', '客户联系不上'][i % 4]
} else {
// 办理成功无审核状态 (约15%)
businessStatus = '办理成功'
actualReward = estimatedReward
crmOrderNumber = `CRM${dateStr.replace(/-/g, '')}${String(i + 1000).padStart(4, '0')}`
completeTime = `${dateStr} ${String(14 + (i % 8)).padStart(2, '0')}:${String((i * 7) % 60).padStart(2, '0')}`
}
// 添加基础操作日志
operationLogs.push({
id: `LOG${orderId}_001`,
time: `${dateStr} ${String(9 + (i % 4)).padStart(2, '0')}:${String((i * 13) % 60).padStart(2, '0')}`,
operator: name,
action: '登记订单',
details: `能人登记新订单,等待办理。业务类型:${businessName}`
})
// 根据状态添加相应的操作日志
if (businessStatus === '办理成功') {
operationLogs.push({
id: `LOG${orderId}_002`,
time: completeTime!,
operator: '管理员',
action: '保存办结信息',
details: `CRM订单编号:${crmOrderNumber},移动人员成功办理业务`
})
if (reviewStatus === '审核通过') {
operationLogs.push({
id: `LOG${orderId}_003`,
time: `${dateStr} ${String(16 + (i % 6)).padStart(2, '0')}:${String((i * 17) % 60).padStart(2, '0')}`,
operator: '主管理员',
action: '审核通过',
details: `主管审核通过,金额:¥${actualReward?.toFixed(2)}`
})
} else if (reviewStatus === '审核驳回') {
const rejectReasons = ['金额与实际不符', 'CRM订单号有误', '缺少必要凭证', '客户信息不匹配']
const rejectReason = rejectReasons[i % rejectReasons.length]
operationLogs.push({
id: `LOG${orderId}_003`,
time: `${dateStr} ${String(16 + (i % 6)).padStart(2, '0')}:${String((i * 17) % 60).padStart(2, '0')}`,
operator: '主管理员',
action: '审核驳回',
details: `驳回原因:${rejectReason}`
})
}
} else if (businessStatus === '已关闭') {
const closeReasons = ['客户取消办理', '业务规则变更', '重复订单', '客户联系不上']
const closeReason = closeReasons[i % closeReasons.length]
operationLogs.push({
id: `LOG${orderId}_002`,
time: completeTime!,
operator: '管理员',
action: '关闭订单',
details: `关闭原因:${closeReason}`
})
}
mockOrders.push({
id: orderId,
registerPersonPhone: phone,
registerPersonName: name,
customerPhone: customerPhone,
businessName: businessName,
registerTime: `${dateStr} ${String(9 + (i % 4)).padStart(2, '0')}:${String((i * 13) % 60).padStart(2, '0')}`,
businessStatus: businessStatus,
reviewStatus: reviewStatus,
estimatedReward: estimatedReward,
actualReward: actualReward,
crmOrderNumber: crmOrderNumber,
completeTime: completeTime,
paymentTime: reviewStatus === '审核通过' ? `${dateStr} ${String(16 + (i % 6)).padStart(2, '0')}:${String((i * 17) % 60).padStart(2, '0')}` : undefined,
rejectReason: reviewStatus === '审核驳回' ? ['金额与实际不符', 'CRM订单号有误', '缺少必要凭证', '客户信息不匹配'][i % 4] : undefined,
closeReason: businessStatus === '已关闭' ? ['客户取消办理', '业务规则变更', '重复订单', '客户联系不上'][i % 4] : undefined,
remarks: i % 8 === 0 ? '客户要求尽快办理' : i % 12 === 0 ? '客户地址偏远' : undefined,
processRemark: businessStatus !== '待办理' ? `办理备注信息${i + 1}` : undefined,
operationLogs: operationLogs
})
}
return mockOrders
}
// 计算属性
const uniqueBusinessNames = ref([])
const uniqueBusinessNames = ref<any[]>([])
const totalPages = ref('')
const totalElements = ref('')
const paginatedOrders = ref([])
const paginatedOrders = ref<any[]>([])
// 状态样式映射 - 使用浅色背景样式
const getBusinessStatusClass = (status: BusinessStatus) => {
const statusMap = {
const statusMap: Record<string, string> = {
'-1': 'bg-blue-100 text-blue-800',
'1': 'bg-green-100 text-green-800',
'0': 'bg-gray-100 text-gray-800'
'0': 'bg-gray-100 text-gray-800',
'待办理': 'bg-blue-100 text-blue-800',
'办理成功': 'bg-green-100 text-green-800',
'已关闭': 'bg-gray-100 text-gray-800'
}
return statusMap[status] || 'bg-gray-100 text-gray-800'
}
const getBusinessStatusName = (status: BusinessStatus) => {
const statusMap = {
const statusMap: Record<string, string> = {
'-1': '待办理',
'1': '办理成功',
'0': '已关闭'
'0': '已关闭',
'待办理': '待办理',
'办理成功': '办理成功',
'已关闭': '已关闭'
}
return statusMap[status] || ''
}
const getReviewStatusClass = (status: ReviewStatus) => {
const statusMap = {
const statusMap: Record<string, string> = {
'0': 'bg-purple-100 text-purple-800',
'1': 'bg-green-100 text-green-800',
'2': 'bg-orange-100 text-orange-800'
'2': 'bg-orange-100 text-orange-800',
'待审核': 'bg-purple-100 text-purple-800',
'审核通过': 'bg-green-100 text-green-800',
'审核驳回': 'bg-orange-100 text-orange-800'
}
return statusMap[status] || 'bg-gray-100 text-gray-800'
}
const getReviewStatusName = (status: ReviewStatus) => {
const statusMap = {
const statusMap: Record<string, string> = {
'0': '待审核',
'1': '审核通过',
'2': '审核驳回'
'2': '审核驳回',
'待审核': '待审核',
'审核通过': '审核通过',
'审核驳回': '审核驳回'
}
return statusMap[status] || '--'
}
......@@ -1019,7 +873,7 @@ const handleConfirmBatchReject = async () => {
return
}
let list = []
let list: any[] = []
batchReviewOrders.value.forEach(order => {
list.push({
id: order.id,
......@@ -1055,7 +909,7 @@ const handleConfirmBatchApprove = async () => {
return
}
let list = []
let list: any[] = []
batchReviewOrders.value.forEach(order => {
list.push({
id: order.id,
......@@ -1262,14 +1116,6 @@ const applyBatchModify = () => {
// 初始化数据
onMounted(() => {
if (props.orders.length === 0) {
const newOrders = generateMockOrders()
orders.value = newOrders
emit('orders-update', newOrders)
} else {
orders.value = props.orders
}
queryOrder()
queryRule()
})
......
......@@ -116,6 +116,8 @@
</div>
<el-switch
v-model="roleStatusEnabled"
active-text="开启"
inactive-text="关闭"
/>
</div>
</div>
......@@ -126,13 +128,13 @@
<label class="block text-sm font-medium text-neutral-900">
权限选择 <span class="text-red-500">*</span>
</label>
<el-tag
<!-- <el-tag
type="primary"
effect="plain"
class="bg-brand-primary/10 text-brand-primary border-brand-primary"
>
已选择 {{ selectedPermissions.length }} 个权限
</el-tag>
</el-tag> -->
</div>
<div class="border border-neutral-300 rounded p-4 bg-neutral-50 max-h-96 overflow-y-auto">
......@@ -214,6 +216,7 @@ export interface Permission {
export interface Role {
id: Number
name: string
roleName?: string
level: '地市级' | '区县级' | '一线人员'
status: RoleStatus
remark?: string
......@@ -313,7 +316,7 @@ const handleOpenAddDialog = () => {
// 打开编辑对话框
const handleOpenEditDialog = async (role: Role) => {
editingRole.value = role
roleName.value = role.roleName
roleName.value = role.roleName || ''
roleDescription.value = role.remark || ''
roleStatusEnabled.value = role.status === 1
......
<script setup lang="ts">
import WelcomeItem from './WelcomeItem.vue'
// import WelcomeItem from './WelcomeItem.vue' // 文件不存在,暂时注释
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
......
......@@ -248,6 +248,8 @@
</div>
<el-switch
v-model="formData.isActive"
active-text=""
inactive-text="按年付费"
/>
</div>
</div>
......@@ -271,7 +273,7 @@
:role-id="formData.roleId"
:roles="roles"
:expanded-ids="organizationExpandedIds"
:account-type="formData.accountType"
:account-type="formData.accountType as any "
@select="handleOrganizationSelect"
@toggle-expand="handleToggleExpand"
/>
......@@ -304,10 +306,12 @@
</div>
</div>
</div>
<template #footer>
<el-button @click="isDialogOpen = false">取消</el-button>
<el-button type="primary" @click="handleSave">确定</el-button>
</template>
</el-dialog>
</div>
</template>
......@@ -324,7 +328,7 @@ export interface User {
realName: string
organizationId: string
roleId: string
accountType?: '1' | '2' | '3'
accountType?: string
phone?: string
email?: string
status: '1' | '0',
......@@ -368,7 +372,7 @@ const userNameSearch = ref('')
const phoneSearch = ref('')
const codeSearch = ref('')
const roleFilter = ref<string>('all')
const accountTypeFilter = ref<'' | '1' | '2' | '3'>('')
const accountTypeFilter = ref<string>('')
const statusFilter = ref<'' | '1' | '0'>('')
const organizationFilter = ref<string>('')
const organizationExpandedIds = ref(new Set<string>())
......@@ -377,7 +381,7 @@ const formData = ref({
username: '',
realName: '',
phone: '',
accountType: '',
accountType: '1',
organizationId: '',
roleId: '',
isActive: true
......@@ -524,16 +528,6 @@ const handleOpenEditDialog = (row: any) => {
const handleAccountTypeChange = () => {
// 当账号类型变更时,清空组织选择
formData.value.organizationId = ''
// 根据账号类型设置组织选择的层级限制
const accountType = formData.value.accountType
if (accountType === '地市级') {
ElMessage.info('账号类型为地市级,所属组织只能选择地市级')
} else if (accountType === '区县级') {
ElMessage.info('账号类型为区县级,所属组织只能选择区县级')
} else if (accountType === '一线人员') {
ElMessage.info('账号类型为一线人员,所属组织只能选择客户经理团队')
}
}
const handleRoleChange = () => {
// 角色变更时不进行层级检查
......@@ -580,25 +574,6 @@ const expandToOrganization = (targetOrgId: string) => {
console.warn('未找到目标组织:', targetOrgId)
}
}
const isOrganizationSelectable = (orgType: string, roleId: string): boolean => {
// 只根据账号类型进行组织层级限制,不根据角色层级限制
const accountType = formData.value.accountType
switch (accountType) {
case '地市级':
// 地市级只能选择地市级组织
return orgType === '地市'
case '区县级':
// 区县级只能选择区县级组织
return orgType === '区县'
case '一线人员':
// 一线人员只能选择客户经理团队
return orgType === '客户经理团队'
default:
// 如果没有选择账号类型,可以选择所有组织
return true
}
}
const handleSave = async () => {
// 表单验证
if (!formData.value.username.trim()) {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!