style: 优化审核弹窗UI风格,统一使用Ant Design组件

优化内容:

1. 组件替换
   ✅ 使用 Button 替换原生 button
   ✅ 使用 Select 替换原生 select
   ✅ 使用 InputNumber 替换 input[type=number]
   ✅ 使用 Space 组件优化布局
   ✅ 使用 Tag 组件显示标签

2. 任务类型编辑区域
   ✅ 改用浅灰背景 (#fafafa)
   ✅ 边框颜色统一 (#e8e8e8)
   ✅ 任务类型显示为蓝色 Tag
   ✅ 使用 InputNumber 组件调整数量
   ✅ 删除按钮使用 text + danger 样式
   ✅ 添加按钮使用 primary + 绿色样式

3. 接单方式选择
   ✅ Radio 选项卡片化设计
   ✅ 选中状态浅蓝背景 (#e6f7ff)
   ✅ 添加图标前缀 (🏢/👤)
   ✅ 卡片圆角 6px
   ✅ 过渡动画效果

4. 设计师列表
   ✅ 卡片化设计,选中高亮
   ✅ 使用 Tag 显示任务数量
   ✅ 根据任务量显示不同颜色:
      - 0-3个:success (绿色)
      - 4-5个:warning (橙色)
      - 6+个:error (红色)

5. 弹窗样式
   ✅ 标题添加 emoji 图标
   ✅ 宽度调整为 650px
   ✅ 按钮尺寸统一为 large
   ✅ 按钮最小宽度 100px

6. 驳回弹窗
   ✅ 同样优化风格
   ✅ 增加内边距
   ✅ 文本域高度增加到 5 行
   ✅ 统一按钮样式

整体效果:
- 与系统其他页面风格一致
- 使用 Ant Design 标准组件
- 视觉层次更清晰
- 交互体验更友好
- 响应式过渡动画
This commit is contained in:
Your Name 2026-01-03 12:07:54 +08:00
parent 9d431d0f0e
commit 7e970fa614

View File

@ -1953,7 +1953,7 @@
<script setup lang="ts">
import { ref, reactive, computed, onMounted, onUnmounted, h } from 'vue'
import { useRouter } from 'vue-router'
import { message, Modal, InputNumber, Textarea, Radio, RadioGroup } from 'ant-design-vue'
import { message, Modal, InputNumber, Textarea, Radio, RadioGroup, Button, Select, Space, Tag } from 'ant-design-vue'
import DefaultLayout from '@/layouts/DefaultLayout.vue'
import Icon from '@/components/Icon.vue'
import * as taskApi from '@/api/task'
@ -2570,53 +2570,89 @@ const showAssignDesignerModal = async (task: Task) => {
quantity: task.quantity || 1
}))
let newTaskTypeId: number | null = null
const modalContent = h('div', { style: 'padding: 10px 0;' }, [
// 任务类型编辑区域
h('div', { style: 'marginBottom: 24px; padding: 16px; background: #f5f5f5; borderRadius: 8px;' }, [
h('h4', { style: 'marginBottom: 12px; fontSize: 14px; fontWeight: 600;' }, '📝 编辑任务类型'),
h('div', { style: 'marginBottom: 12px;' }, [
h('div', {
style: {
marginBottom: '24px',
padding: '16px',
background: '#fafafa',
borderRadius: '8px',
border: '1px solid #e8e8e8'
}
}, [
h('div', { style: 'marginBottom: 16px; display: flex; alignItems: center;' }, [
h('span', {
style: {
fontSize: '14px',
fontWeight: 600,
color: '#1890ff',
marginRight: '8px'
}
}, '📝'),
h('span', {
style: {
fontSize: '14px',
fontWeight: 600,
color: '#262626'
}
}, '编辑任务类型')
]),
h(Space, {
direction: 'vertical',
size: 8,
style: { width: '100%', marginBottom: '12px' }
}, [
...editableTaskTypes.map((item, index) =>
h('div', {
key: index,
style: {
display: 'flex',
alignItems: 'center',
marginBottom: '8px',
padding: '8px',
padding: '12px',
background: 'white',
borderRadius: '4px',
border: '1px solid #d9d9d9'
borderRadius: '6px',
border: '1px solid #e8e8e8',
transition: 'all 0.3s'
}
}, [
h('span', { style: { flex: 1, fontSize: 13 } },
getTaskTypeName(item.typeId)
),
h('span', { style: { marginRight: 8, fontSize: 12, color: '#666' } }, '数量:'),
h('input', {
type: 'number',
h(Tag, {
color: 'blue',
style: {
marginRight: '12px',
fontSize: '13px',
padding: '4px 12px'
}
}, getTaskTypeName(item.typeId)),
h('span', {
style: {
flex: 1,
fontSize: '13px',
color: '#8c8c8c'
}
}),
h('span', {
style: {
marginRight: '8px',
fontSize: '13px',
color: '#595959'
}
}, '数量:'),
h(InputNumber, {
value: item.quantity,
min: 1,
style: {
width: '60px',
padding: '4px 8px',
border: '1px solid #d9d9d9',
borderRadius: '4px',
marginRight: '8px'
},
onInput: (e: any) => {
item.quantity = parseInt(e.target.value) || 1
size: 'small',
style: { width: '80px', marginRight: '8px' },
onChange: (val: number) => {
item.quantity = val || 1
}
}),
h('button', {
style: {
padding: '4px 12px',
background: '#ff4d4f',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: 12
},
h(Button, {
type: 'text',
danger: true,
size: 'small',
onClick: () => {
editableTaskTypes.splice(index, 1)
}
@ -2624,39 +2660,32 @@ const showAssignDesignerModal = async (task: Task) => {
])
)
]),
h('div', { style: 'display: flex; gap: 8px;' }, [
h('select', {
id: 'newTaskTypeSelect',
style: {
flex: 1,
padding: '6px 12px',
border: '1px solid #d9d9d9',
borderRadius: '4px',
fontSize: 13
}
}, [
h('option', { value: '' }, '-- 选择要添加的任务类型 --'),
...demandTypes.value.map((type: any) =>
h('option', { value: type.id }, type.name)
)
]),
h('button', {
style: {
padding: '6px 16px',
background: '#52c41a',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: 13
h(Space, { size: 8, style: { width: '100%' } }, [
h(Select, {
value: newTaskTypeId,
placeholder: '选择要添加的任务类型',
allowClear: true,
style: { flex: 1, minWidth: '200px' },
onChange: (val: number) => {
newTaskTypeId = val
},
options: demandTypes.value.map((type: any) => ({
value: type.id,
label: type.name
}))
}),
h(Button, {
type: 'primary',
size: 'middle',
style: { background: '#52c41a', borderColor: '#52c41a' },
onClick: () => {
const selectEl = document.getElementById('newTaskTypeSelect') as HTMLSelectElement
const typeId = parseInt(selectEl.value)
if (typeId && !editableTaskTypes.find(t => t.typeId === typeId)) {
editableTaskTypes.push({ typeId, quantity: 1 })
} else if (typeId) {
if (newTaskTypeId && !editableTaskTypes.find(t => t.typeId === newTaskTypeId)) {
editableTaskTypes.push({ typeId: newTaskTypeId, quantity: 1 })
newTaskTypeId = null
} else if (newTaskTypeId) {
message.warning('该任务类型已添加')
} else {
message.warning('请先选择任务类型')
}
}
}, '+ 添加类型')
@ -2664,33 +2693,66 @@ const showAssignDesignerModal = async (task: Task) => {
]),
// 选择接单方式
h('p', { style: 'margin-bottom: 16px; color: #666;' },
'选择任务接单方式:'
),
h(RadioGroup, {
value: assignType,
onChange: (e: any) => {
assignType = e.target.value
},
style: { width: '100%', marginBottom: '16px' }
h('div', {
style: {
marginBottom: '24px'
}
}, [
h(Radio, { value: 'auto', style: { display: 'block', marginBottom: '12px' } },
'发布到任务大厅(设计师自由抢单)'
),
h(Radio, { value: 'manual', style: { display: 'block' } },
'指定设计师接单'
)
h('div', {
style: {
marginBottom: '12px',
fontSize: '14px',
fontWeight: 500,
color: '#262626'
}
}, '选择任务接单方式'),
h(RadioGroup, {
value: assignType,
onChange: (e: any) => {
assignType = e.target.value
},
style: { width: '100%' }
}, [
h(Radio, {
value: 'auto',
style: {
display: 'block',
marginBottom: '12px',
padding: '10px 12px',
border: '1px solid #d9d9d9',
borderRadius: '6px',
background: assignType === 'auto' ? '#e6f7ff' : 'white',
transition: 'all 0.3s'
}
}, '🏢 发布到任务大厅(设计师自由抢单)'),
h(Radio, {
value: 'manual',
style: {
display: 'block',
padding: '10px 12px',
border: '1px solid #d9d9d9',
borderRadius: '6px',
background: assignType === 'manual' ? '#e6f7ff' : 'white',
transition: 'all 0.3s'
}
}, '👤 指定设计师接单')
])
]),
// 设计师列表(仅在指定接单时显示)
h('div', {
style: {
marginTop: '16px',
display: assignType === 'manual' ? 'block' : 'none'
}
}, [
h('p', { style: { marginBottom: '12px', color: '#666', fontSize: '13px' } },
'选择设计师(显示当前进行中的任务数量):'
),
h('div', {
style: {
marginBottom: '12px',
fontSize: '14px',
fontWeight: 500,
color: '#262626'
}
}, '选择设计师'),
h(RadioGroup, {
value: selectedDesignerId,
onChange: (e: any) => {
@ -2703,32 +2765,38 @@ const showAssignDesignerModal = async (task: Task) => {
style: {
display: 'flex',
alignItems: 'center',
marginBottom: '8px',
padding: '8px',
border: '1px solid #f0f0f0',
borderRadius: '4px'
marginBottom: '10px',
padding: '12px',
border: '1px solid #e8e8e8',
borderRadius: '6px',
background: selectedDesignerId === designer.id ? '#e6f7ff' : 'white',
transition: 'all 0.3s'
}
}, [
h('span', { style: { flex: 1 } }, designer.realName),
h('span', {
style: {
color: designer.inProgressCount > 5 ? '#ff4d4f' :
designer.inProgressCount > 3 ? '#faad14' : '#52c41a',
fontSize: '12px',
marginLeft: '12px'
}
}, `进行中: ${designer.inProgressCount} 个任务`)
h('span', { style: { flex: 1, fontSize: '14px', fontWeight: 500 } }, designer.realName),
h(Tag, {
color: designer.inProgressCount > 5 ? 'error' :
designer.inProgressCount > 3 ? 'warning' : 'success'
}, `进行中: ${designer.inProgressCount}`)
])
))
])
])
Modal.confirm({
title: '接单部门审核通过',
title: '✅ 接单部门审核通过',
content: modalContent,
width: 600,
width: 650,
okText: '确认通过',
cancelText: '取消',
okButtonProps: {
size: 'large',
style: { minWidth: '100px' }
},
cancelButtonProps: {
size: 'large',
style: { minWidth: '100px' }
},
onOk: async () => {
try {
approvalLoading.value = true
@ -2791,22 +2859,39 @@ const handleRejectTwoLevelTask = async (task: Task) => {
let rejectReason = ''
Modal.confirm({
title: '驳回任务',
content: h('div', { style: 'padding: 10px 0;' }, [
h('p', { style: 'margin-bottom: 10px; color: #666;' }, '请输入驳回原因:'),
title: '❌ 驳回任务',
content: h('div', { style: 'padding: 16px 0;' }, [
h('div', {
style: {
marginBottom: '12px',
fontSize: '14px',
fontWeight: 500,
color: '#262626'
}
}, '请输入驳回原因'),
h(Textarea, {
rows: 4,
placeholder: '请详细说明驳回原因,以便发起人修改',
rows: 5,
placeholder: '请详细说明驳回原因,以便发起人修改...',
maxlength: 500,
showCount: true,
style: { fontSize: '14px' },
onChange: (e: any) => {
rejectReason = e.target.value
}
})
]),
width: 550,
okText: '确认驳回',
cancelText: '取消',
okType: 'danger',
okButtonProps: {
size: 'large',
style: { minWidth: '100px' }
},
cancelButtonProps: {
size: 'large',
style: { minWidth: '100px' }
},
onOk: async () => {
if (!rejectReason || !rejectReason.trim()) {
message.warning('请输入驳回原因')