会议纪要功能修复与改进
后端: - 待办同步改走 ISysOaTaskService.insertByBo/updateByBo,新任务带操作日志和IM通知 - 任务状态映射修正:done→2执行完成,其余→0执行中(原 progress→1 会显示成"等待验收") - 无负责人/无内容的待办仅作纪要记录,不再生成无主任务 - 更新时可清空字段改用显式 set(原来解绑项目、清空内容不生效) - 新增接口返回纪要ID,前端据此进入编辑态,避免重复保存生成多条 - 会议编号加3位随机数防同秒撞唯一键;异常改 ServiceException;同步失败记日志 - enrich 为待办条目注入 assigneeName,列表/详情/导出可显示负责人姓名 - SysOaTaskServiceImpl.insertByBo 回填 taskId 供调用方关联 前端: - 主持人/待办负责人改用人员单选弹窗(原多选组件取首位的方式易误操作) - 会议类型、待办状态接入 sys_dict 字典(oa_meeting_type / oa_meeting_task_status) - 新建保存后切换为编辑态;默认日期用本地时区(原 UTC 凌晨会差一天) - 导出/打印带主持人、参会人、待办负责人姓名(原来只有用户ID) - 删除已同步待办时提示任务不会被删除 SQL(已直接应用到生产库): - 字典数据补全并修复 dict_id=0 脏数据(sys_dict_* 主键为雪花ID须显式指定) - 菜单 2063809716454174722 icon 修为 documentation,授权10个角色 - 脚本改为幂等,去掉 DROP TABLE,del_flag 注释修正为逻辑删除值2 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
<el-button size="small" :type="isRecording ? 'danger' : 'warning'"
|
||||
:icon="isRecording ? 'el-icon-video-pause' : 'el-icon-microphone'"
|
||||
@click="cmdRecord">{{ isRecording ? '停止录音' : '语音录入' }}</el-button>
|
||||
<el-button size="small" type="primary" icon="el-icon-document-checked" @click="cmdSave">保存</el-button>
|
||||
<el-button size="small" type="primary" icon="el-icon-document-checked"
|
||||
:loading="saving" @click="cmdSave">保存</el-button>
|
||||
<el-button size="small" icon="el-icon-download" @click="cmdExport">导出</el-button>
|
||||
<el-button size="small" icon="el-icon-printer" @click="cmdPrint">打印</el-button>
|
||||
</div>
|
||||
@@ -37,22 +38,22 @@
|
||||
<el-button type="text" icon="el-icon-plus" @click="cmdNew">新建</el-button>
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<el-input v-model="historyQuery.keyword" size="mini" placeholder="搜索主题 / 地点"
|
||||
<el-input v-model="historyQuery.keyword" size="mini" placeholder="搜索编号 / 主题 / 地点"
|
||||
clearable prefix-icon="el-icon-search"
|
||||
@keyup.enter.native="loadHistory" @clear="loadHistory" />
|
||||
@keyup.enter.native="searchHistory" @clear="searchHistory" />
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<project-select v-model="historyQuery.projectId" placeholder="项目筛选" clearable
|
||||
size="mini" style="flex:1" @input="loadHistory" />
|
||||
size="mini" style="flex:1" @input="searchHistory" />
|
||||
<el-select v-model="historyQuery.meetingType" size="mini" clearable placeholder="类型"
|
||||
style="width:90px;margin-left:4px" @change="loadHistory">
|
||||
<el-option v-for="t in meetingTypes" :key="t.value" :value="t.value" :label="t.label" />
|
||||
style="width:90px;margin-left:4px" @change="searchHistory">
|
||||
<el-option v-for="t in dict.type.oa_meeting_type" :key="t.value" :value="t.value" :label="t.label" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<el-date-picker v-model="historyQuery.dateRange" type="daterange" size="mini" range-separator="~"
|
||||
start-placeholder="开始" end-placeholder="结束" value-format="yyyy-MM-dd"
|
||||
style="width:100%" @change="loadHistory" />
|
||||
style="width:100%" @change="searchHistory" />
|
||||
</div>
|
||||
|
||||
<div v-loading="historyLoading" class="hist-list">
|
||||
@@ -64,15 +65,13 @@
|
||||
@click="loadMinutes(m.id)">
|
||||
<div class="hc-top">
|
||||
<span class="hc-code">{{ m.meetingCode }}</span>
|
||||
<el-tag size="mini" :type="typeTag(m.meetingType)" effect="plain">
|
||||
{{ typeLabel(m.meetingType) }}
|
||||
</el-tag>
|
||||
<dict-tag :options="dict.type.oa_meeting_type" :value="m.meetingType" />
|
||||
<el-button type="text" icon="el-icon-delete" class="hc-del"
|
||||
@click.stop="removeMinutes(m)" />
|
||||
</div>
|
||||
<div class="hc-subject">{{ m.subject }}</div>
|
||||
<div class="hc-line"><i class="el-icon-date" /> {{ m.meetingDate }}
|
||||
<span v-if="m.projectNum" class="hc-proj">· {{ m.projectNum }}</span>
|
||||
<span v-if="m.projectName" class="hc-proj">· {{ m.projectName }}</span>
|
||||
</div>
|
||||
<div v-if="m.hostUserName" class="hc-line"><i class="el-icon-s-custom" /> 主持:{{ m.hostUserName }}</div>
|
||||
<div v-if="m.location" class="hc-line"><i class="el-icon-location-outline" /> {{ m.location }}</div>
|
||||
@@ -106,33 +105,35 @@
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目">
|
||||
<project-select v-model="form.projectId" placeholder="选择项目" clearable style="width:100%" />
|
||||
<project-select v-model="form.projectId" placeholder="不选则为非项目会议" clearable style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="会议类型">
|
||||
<el-select v-model="form.meetingType" style="width:100%">
|
||||
<el-option v-for="t in meetingTypes" :key="t.value" :value="t.value" :label="t.label" />
|
||||
<el-option v-for="t in dict.type.oa_meeting_type" :key="t.value" :value="t.value" :label="t.label" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item label="会议主题" required>
|
||||
<el-input v-model="form.subject" placeholder="输入会议主题" />
|
||||
<el-input v-model="form.subject" maxlength="200" placeholder="输入会议主题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="会议地点">
|
||||
<el-input v-model="form.location" placeholder="会议室 / 线上" />
|
||||
<el-input v-model="form.location" maxlength="100" placeholder="会议室 / 线上" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="主持人">
|
||||
<user-select :value="hostCsv" @input="onHostInput" />
|
||||
<div class="help-tip">仅取首位为主持人;如要换人请先点 ×。</div>
|
||||
<el-tag v-if="form.hostUserId" closable @close="clearHost">
|
||||
{{ form.hostUserName || ('#' + form.hostUserId) }}
|
||||
</el-tag>
|
||||
<el-button type="text" @click="pickHost">{{ form.hostUserId ? '更换' : '点击选择' }}</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col :span="16">
|
||||
<el-form-item label="参会人员">
|
||||
<user-select v-model="form.attendeeUserIds" />
|
||||
</el-form-item>
|
||||
@@ -172,7 +173,7 @@
|
||||
<div class="sec-block">
|
||||
<div class="sec-hd">
|
||||
<span class="sec-num">四</span> 待办事项
|
||||
<span class="sec-tip">保存时按上方开关自动同步到 OA 任务</span>
|
||||
<span class="sec-tip">填了负责人和内容的待办,保存时按上方开关同步为 OA 任务并通知负责人</span>
|
||||
<el-button type="text" icon="el-icon-plus" class="add-task" @click="addTask">添加待办</el-button>
|
||||
</div>
|
||||
|
||||
@@ -181,11 +182,18 @@
|
||||
<div class="task-line">
|
||||
<div class="tf tf-assignee">
|
||||
<label>负责人</label>
|
||||
<user-select :value="t._assigneeCsv" @input="onTaskAssigneeChange(t, $event)" />
|
||||
<div>
|
||||
<el-tag v-if="t.assigneeUserId" size="small" closable @close="clearAssignee(t)">
|
||||
{{ t.assigneeName || ('#' + t.assigneeUserId) }}
|
||||
</el-tag>
|
||||
<el-button type="text" size="mini" @click="pickAssignee(i)">
|
||||
{{ t.assigneeUserId ? '更换' : '选择' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tf tf-content">
|
||||
<label>任务内容</label>
|
||||
<el-input v-model="t.content" size="mini" placeholder="任务描述..." />
|
||||
<el-input v-model="t.content" size="mini" maxlength="200" placeholder="任务描述..." />
|
||||
</div>
|
||||
<div class="tf tf-deadline">
|
||||
<label>截止日期</label>
|
||||
@@ -195,7 +203,8 @@
|
||||
<div class="tf tf-status">
|
||||
<label>状态</label>
|
||||
<el-select v-model="t.status" size="mini" style="width:100%">
|
||||
<el-option v-for="o in taskStatusOpts" :key="o.value" :value="o.value" :label="o.label" />
|
||||
<el-option v-for="o in dict.type.oa_meeting_task_status" :key="o.value"
|
||||
:value="o.value" :label="o.label" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="tf tf-act">
|
||||
@@ -209,6 +218,9 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 人员单选弹窗(主持人 / 待办负责人共用) -->
|
||||
<user-single-select ref="userPicker" v-model="userPickerVisible" @onSelected="onUserPicked" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -218,33 +230,28 @@ import {
|
||||
updateMeetingMinutes, delMeetingMinutes
|
||||
} from '@/api/oa/meetingMinutes'
|
||||
import UserSelect from '@/components/UserSelect'
|
||||
import UserSingleSelect from '@/components/UserSelect/single'
|
||||
import ProjectSelect from '@/components/fad-service/ProjectSelect'
|
||||
|
||||
const MEETING_TYPES = [
|
||||
{ value: 'tech', label: '技术评审' },
|
||||
{ value: 'project', label: '项目推进' },
|
||||
{ value: 'client', label: '客户沟通' },
|
||||
{ value: 'weekly', label: '周例会' },
|
||||
{ value: 'other', label: '其他' }
|
||||
]
|
||||
const TASK_STATUS = [
|
||||
{ value: 'pending', label: '待办' },
|
||||
{ value: 'progress', label: '进行中' },
|
||||
{ value: 'done', label: '已完成' }
|
||||
]
|
||||
const TYPE_TAG = { tech: 'info', project: 'primary', client: 'warning', weekly: 'success', other: '' }
|
||||
function localToday () {
|
||||
const d = new Date()
|
||||
const p = n => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`
|
||||
}
|
||||
|
||||
function emptyForm () {
|
||||
return {
|
||||
id: null,
|
||||
meetingCode: '',
|
||||
meetingDate: new Date().toISOString().slice(0, 10),
|
||||
meetingDate: localToday(),
|
||||
projectId: null,
|
||||
meetingType: 'tech',
|
||||
meetingType: 'other',
|
||||
subject: '',
|
||||
location: '',
|
||||
hostUserId: null,
|
||||
hostUserName: '',
|
||||
attendeeUserIds: '',
|
||||
attendeeUserNames: '',
|
||||
topic: '',
|
||||
discussion: '',
|
||||
decision: '',
|
||||
@@ -255,15 +262,14 @@ function emptyForm () {
|
||||
|
||||
export default {
|
||||
name: 'OaMeeting',
|
||||
components: { UserSelect, ProjectSelect },
|
||||
components: { UserSelect, UserSingleSelect, ProjectSelect },
|
||||
dicts: ['oa_meeting_type', 'oa_meeting_task_status'],
|
||||
data () {
|
||||
return {
|
||||
meetingTypes: MEETING_TYPES,
|
||||
taskStatusOpts: TASK_STATUS,
|
||||
|
||||
statusType: 'success',
|
||||
statusText: '就绪',
|
||||
protoWarn: false,
|
||||
saving: false,
|
||||
|
||||
form: emptyForm(),
|
||||
|
||||
@@ -280,8 +286,9 @@ export default {
|
||||
voiceFinalText: '',
|
||||
voiceInterim: '',
|
||||
|
||||
/** 主持人 CSV — 直接绑 UserSelect。@input 单向同步到 form.hostUserId(取首位) */
|
||||
hostCsv: ''
|
||||
// 人员单选弹窗当前服务对象:'host' 或待办行下标
|
||||
userPickerVisible: false,
|
||||
userPickerTarget: 'host'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@@ -296,29 +303,58 @@ export default {
|
||||
const local = host === 'localhost' || host === '127.0.0.1'
|
||||
this.protoWarn = !(location.protocol === 'https:' || local)
|
||||
},
|
||||
typeLabel (v) { return (MEETING_TYPES.find(t => t.value === v) || {}).label || '其他' },
|
||||
typeTag (v) { return TYPE_TAG[v] || '' },
|
||||
dictLabel (dictKey, v) {
|
||||
const hit = (this.dict.type[dictKey] || []).find(t => t.value === v)
|
||||
return hit ? hit.label : (v || '-')
|
||||
},
|
||||
|
||||
/** UserSelect 是多选;主持人只保留首位 */
|
||||
onHostInput (val) {
|
||||
const arr = typeof val === 'string' ? val.split(',').filter(Boolean) : (val || [])
|
||||
this.hostCsv = arr.length ? String(arr[0]) : ''
|
||||
this.form.hostUserId = arr.length ? Number(arr[0]) : null
|
||||
// ============ 人员选择 ============
|
||||
pickHost () {
|
||||
this.userPickerTarget = 'host'
|
||||
this.userPickerVisible = true
|
||||
},
|
||||
clearHost () {
|
||||
this.form.hostUserId = null
|
||||
this.form.hostUserName = ''
|
||||
},
|
||||
pickAssignee (i) {
|
||||
this.userPickerTarget = i
|
||||
this.userPickerVisible = true
|
||||
},
|
||||
clearAssignee (t) {
|
||||
t.assigneeUserId = null
|
||||
t.assigneeName = ''
|
||||
},
|
||||
onUserPicked (row) {
|
||||
if (!row) return
|
||||
if (this.userPickerTarget === 'host') {
|
||||
this.form.hostUserId = row.userId
|
||||
this.form.hostUserName = row.nickName
|
||||
} else {
|
||||
const t = this.form.tasks[this.userPickerTarget]
|
||||
if (t) {
|
||||
t.assigneeUserId = row.userId
|
||||
t.assigneeName = row.nickName
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// ============ 待办 ============
|
||||
addTask () {
|
||||
this.form.tasks.push({
|
||||
assigneeUserId: null, _assigneeCsv: '',
|
||||
assigneeUserId: null, assigneeName: '',
|
||||
content: '', deadline: '', status: 'pending', taskId: null
|
||||
})
|
||||
},
|
||||
removeTask (i) { this.form.tasks.splice(i, 1) },
|
||||
/** 待办负责人 UserSelect 多选 → 取首位 */
|
||||
onTaskAssigneeChange (task, val) {
|
||||
const arr = typeof val === 'string' ? val.split(',').filter(Boolean) : (val || [])
|
||||
task.assigneeUserId = arr.length ? Number(arr[0]) : null
|
||||
task._assigneeCsv = arr.length ? String(arr[0]) : ''
|
||||
removeTask (i) {
|
||||
const t = this.form.tasks[i]
|
||||
if (t.taskId) {
|
||||
this.$modal.confirm('该待办已同步为 OA 任务,移除后任务本身不会删除,仅与纪要解除关联。继续?')
|
||||
.then(() => this.form.tasks.splice(i, 1))
|
||||
.catch(() => {})
|
||||
} else {
|
||||
this.form.tasks.splice(i, 1)
|
||||
}
|
||||
},
|
||||
|
||||
// ============ 新建 / 保存 ============
|
||||
@@ -326,16 +362,14 @@ export default {
|
||||
const keepProject = this.form.projectId
|
||||
this.form = emptyForm()
|
||||
if (keepProject) this.form.projectId = keepProject
|
||||
this.hostCsv = ''
|
||||
this.clearVoice()
|
||||
this.$modal.msgSuccess('已新建纪要')
|
||||
},
|
||||
async cmdSave () {
|
||||
if (!this.form.meetingDate) return this.$modal.msgError('请选择会议日期')
|
||||
if (!this.form.subject) return this.$modal.msgError('请输入会议主题')
|
||||
// 序列化时清掉 _assigneeCsv 临时字段
|
||||
const cleanTasks = (this.form.tasks || []).map(t => ({
|
||||
assigneeUserId: t.assigneeUserId,
|
||||
assigneeName: t.assigneeName,
|
||||
content: t.content,
|
||||
deadline: t.deadline,
|
||||
status: t.status,
|
||||
@@ -343,20 +377,32 @@ export default {
|
||||
}))
|
||||
const payload = { ...this.form, tasksJson: JSON.stringify(cleanTasks) }
|
||||
delete payload.tasks
|
||||
this.saving = true
|
||||
try {
|
||||
if (this.form.id) await updateMeetingMinutes(payload)
|
||||
else await addMeetingMinutes(payload)
|
||||
let id = this.form.id
|
||||
if (id) {
|
||||
await updateMeetingMinutes(payload)
|
||||
} else {
|
||||
const res = await addMeetingMinutes(payload)
|
||||
id = res.data
|
||||
}
|
||||
this.setStatus('已保存', 'success')
|
||||
setTimeout(() => this.setStatus('就绪', 'success'), 2000)
|
||||
this.$modal.msgSuccess('纪要已保存' + (this.form.syncTask ? ',待办已同步到 OA 任务' : ''))
|
||||
await this.loadHistory()
|
||||
if (this.form.id) await this.loadMinutes(this.form.id, true)
|
||||
if (id) await this.loadMinutes(id, true)
|
||||
} catch (err) {
|
||||
this.$modal.msgError(err.msg || '保存失败')
|
||||
this.setStatus('保存失败', 'warning')
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
},
|
||||
|
||||
// ============ 历史 ============
|
||||
searchHistory () {
|
||||
this.historyQuery.pageNum = 1
|
||||
this.loadHistory()
|
||||
},
|
||||
async loadHistory () {
|
||||
this.historyLoading = true
|
||||
try {
|
||||
@@ -387,14 +433,15 @@ export default {
|
||||
subject: m.subject || '',
|
||||
location: m.location || '',
|
||||
hostUserId: m.hostUserId || null,
|
||||
hostUserName: m.hostUserName || '',
|
||||
attendeeUserIds: m.attendeeUserIds || '',
|
||||
attendeeUserNames: m.attendeeUserNames || '',
|
||||
topic: m.topic || '',
|
||||
discussion: m.discussion || '',
|
||||
decision: m.decision || '',
|
||||
tasks: this.parseTasks(m.tasksJson),
|
||||
syncTask: m.syncTask == null ? 1 : m.syncTask
|
||||
}
|
||||
this.hostCsv = m.hostUserId ? String(m.hostUserId) : ''
|
||||
if (!silent) this.$modal.msgSuccess('已加载:' + m.subject)
|
||||
},
|
||||
parseTasks (s) {
|
||||
@@ -404,7 +451,7 @@ export default {
|
||||
if (!Array.isArray(a)) return []
|
||||
return a.map(t => ({
|
||||
assigneeUserId: t.assigneeUserId || null,
|
||||
_assigneeCsv: t.assigneeUserId ? String(t.assigneeUserId) : '',
|
||||
assigneeName: t.assigneeName || '',
|
||||
content: t.content || '',
|
||||
deadline: t.deadline || '',
|
||||
status: t.status || 'pending',
|
||||
@@ -413,10 +460,10 @@ export default {
|
||||
} catch (e) { return [] }
|
||||
},
|
||||
removeMinutes (m) {
|
||||
this.$modal.confirm(`确认删除「${m.subject}」?此操作不可恢复。`).then(async () => {
|
||||
this.$modal.confirm(`确认删除「${m.subject}」?已同步的 OA 任务不受影响。`).then(async () => {
|
||||
await delMeetingMinutes(m.id)
|
||||
this.$modal.msgSuccess('已删除')
|
||||
if (this.form.id === m.id) this.form = emptyForm()
|
||||
if (this.form.id === m.id) this.cmdNew()
|
||||
await this.loadHistory()
|
||||
}).catch(() => {})
|
||||
},
|
||||
@@ -494,14 +541,15 @@ export default {
|
||||
cmdExport () {
|
||||
if (!this.form.subject) return this.$modal.msgError('无内容可导出')
|
||||
const d = this.form
|
||||
const typeLabel = this.typeLabel(d.meetingType)
|
||||
const statusMap = { pending: '待办', progress: '进行中', done: '已完成' }
|
||||
const lines = []
|
||||
lines.push('德睿福成套设备有限公司 · 会议纪要')
|
||||
lines.push('='.repeat(50))
|
||||
lines.push('日期: ' + d.meetingDate + ' 类型: ' + typeLabel)
|
||||
lines.push('编号: ' + (d.meetingCode || '-'))
|
||||
lines.push('日期: ' + d.meetingDate + ' 类型: ' + this.dictLabel('oa_meeting_type', d.meetingType))
|
||||
lines.push('主题: ' + d.subject)
|
||||
lines.push('地点: ' + (d.location || '-'))
|
||||
lines.push('主持: ' + (d.hostUserName || '-'))
|
||||
lines.push('参会: ' + (d.attendeeUserNames || '-'))
|
||||
lines.push('='.repeat(50))
|
||||
lines.push('')
|
||||
lines.push('一、会议议题'); lines.push('-'.repeat(30)); lines.push(d.topic || '(无)'); lines.push('')
|
||||
@@ -510,8 +558,8 @@ export default {
|
||||
lines.push('四、待办事项'); lines.push('-'.repeat(30))
|
||||
if (d.tasks && d.tasks.length) {
|
||||
d.tasks.forEach(t => {
|
||||
lines.push(' • [#' + (t.assigneeUserId || '-') + '] ' + (t.content || '') +
|
||||
' | 截止:' + (t.deadline || '-') + ' | 状态:' + (statusMap[t.status] || t.status))
|
||||
lines.push(' • [' + (t.assigneeName || '未指派') + '] ' + (t.content || '') +
|
||||
' | 截止:' + (t.deadline || '-') + ' | 状态:' + this.dictLabel('oa_meeting_task_status', t.status))
|
||||
})
|
||||
} else { lines.push('(无)') }
|
||||
lines.push(''); lines.push('='.repeat(50))
|
||||
@@ -528,12 +576,11 @@ export default {
|
||||
const d = this.form
|
||||
const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c =>
|
||||
({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]))
|
||||
const statusMap = { pending: '待办', progress: '进行中', done: '已完成' }
|
||||
let taskHtml = '(无)'
|
||||
if (d.tasks && d.tasks.length) {
|
||||
const rows = d.tasks.map(t =>
|
||||
`<tr><td>#${esc(t.assigneeUserId || '-')}</td><td>${esc(t.content)}</td>` +
|
||||
`<td>${esc(t.deadline || '-')}</td><td>${esc(statusMap[t.status] || t.status)}</td></tr>`
|
||||
`<tr><td>${esc(t.assigneeName || '未指派')}</td><td>${esc(t.content)}</td>` +
|
||||
`<td>${esc(t.deadline || '-')}</td><td>${esc(this.dictLabel('oa_meeting_task_status', t.status))}</td></tr>`
|
||||
).join('')
|
||||
taskHtml = `<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
|
||||
<tr style="background:#eee"><th>负责人</th><th>任务内容</th><th>截止</th><th>状态</th></tr>${rows}</table>`
|
||||
@@ -547,10 +594,13 @@ export default {
|
||||
.meta span{margin-right:18px}.sect{font-size:14px;margin:14px 0 6px;font-weight:700}
|
||||
.body{white-space:pre-wrap;font-size:13px;margin-bottom:16px}
|
||||
@media print{body{padding:20px}}</style></head><body>
|
||||
<h1>德睿福成套设备有限公司</h1><div class="sub">会 议 纪 要</div>
|
||||
<h1>德睿福成套设备有限公司</h1><div class="sub">会 议 纪 要 ${esc(d.meetingCode || '')}</div>
|
||||
<div class="meta"><span>📅 ${esc(d.meetingDate)}</span>
|
||||
<span>📝 ${esc(d.subject)}</span></div>
|
||||
<div class="meta"><span>📍 ${esc(d.location || '-')}</span></div>
|
||||
<span>📝 ${esc(d.subject)}</span>
|
||||
<span>🏷 ${esc(this.dictLabel('oa_meeting_type', d.meetingType))}</span></div>
|
||||
<div class="meta"><span>📍 ${esc(d.location || '-')}</span>
|
||||
<span>🎤 主持:${esc(d.hostUserName || '-')}</span></div>
|
||||
<div class="meta"><span>👥 参会:${esc(d.attendeeUserNames || '-')}</span></div>
|
||||
<div class="sect">一、会议议题</div><div class="body">${esc(d.topic || '(无)')}</div>
|
||||
<div class="sect">二、讨论内容</div><div class="body">${esc(d.discussion || '(无)')}</div>
|
||||
<div class="sect">三、决议事项</div><div class="body">${esc(d.decision || '(无)')}</div>
|
||||
@@ -627,7 +677,6 @@ export default {
|
||||
|
||||
.meta-form {
|
||||
::v-deep .el-form-item { margin-bottom: 8px; }
|
||||
.help-tip { color: #909399; font-size: 11px; line-height: 1.4; }
|
||||
}
|
||||
|
||||
.voice-card {
|
||||
@@ -670,7 +719,7 @@ export default {
|
||||
}
|
||||
.task-line {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr 140px 110px 100px;
|
||||
grid-template-columns: 170px 1fr 140px 110px 100px;
|
||||
gap: 8px; align-items: start;
|
||||
.tf {
|
||||
label { display: block; font-size: 11px; color: #909399; margin-bottom: 2px; }
|
||||
|
||||
Reference in New Issue
Block a user