|
|
|
|
@ -3,59 +3,26 @@
|
|
|
|
|
<!-- 录入态 -->
|
|
|
|
|
<div v-if="!readonly" class="input-container">
|
|
|
|
|
<!-- 已选择/已上传的展示区域 -->
|
|
|
|
|
<div v-if="selectedMeetingMinute || uploadFileList.length > 0" class="selected-display">
|
|
|
|
|
<!-- 已选择会议纪要 -->
|
|
|
|
|
<div v-if="selectedMeetingMinute" class="selected-item selected-oa">
|
|
|
|
|
<el-icon class="item-icon"><Document /></el-icon>
|
|
|
|
|
<!-- 如果有附件URL,链接到附件;否则显示普通文本 -->
|
|
|
|
|
<el-link
|
|
|
|
|
v-if="selectedMeetingMinute.file_url"
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
class="item-title item-title--link"
|
|
|
|
|
:href="selectedMeetingMinute.file_url"
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
{{ selectedMeetingMinute.title }}
|
|
|
|
|
<div v-if="selectedItems.length > 0" class="selected-display">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(item, index) in selectedItems"
|
|
|
|
|
:key="getItemKey(item, index)"
|
|
|
|
|
class="selected-item"
|
|
|
|
|
:class="item.mode === 'oa_meeting_minutes' ? 'selected-oa' : 'selected-upload'"
|
|
|
|
|
>
|
|
|
|
|
<el-icon class="item-icon"><Document v-if="item.mode === 'oa_meeting_minutes'" /><Paperclip v-else /></el-icon>
|
|
|
|
|
<el-link v-if="item.file_url || item.url" type="primary" :underline="false" class="item-title item-title--link" :href="item.file_url || item.url" target="_blank">
|
|
|
|
|
{{ item.title || item.name || '会议纪要' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<span v-else class="item-title">{{ selectedMeetingMinute.title }}</span>
|
|
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
link
|
|
|
|
|
size="small"
|
|
|
|
|
@click="handleViewSelectedDetail"
|
|
|
|
|
class="item-view"
|
|
|
|
|
>
|
|
|
|
|
查看详情
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
type="danger"
|
|
|
|
|
link
|
|
|
|
|
size="small"
|
|
|
|
|
@click="clearSelection"
|
|
|
|
|
class="item-remove"
|
|
|
|
|
>
|
|
|
|
|
<el-icon><Close /></el-icon>
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 已上传文件 -->
|
|
|
|
|
<div v-else-if="uploadFileList.length > 0" class="selected-item selected-upload">
|
|
|
|
|
<el-icon class="item-icon"><Paperclip /></el-icon>
|
|
|
|
|
<span class="item-title">{{ uploadFileList[0].name }}</span>
|
|
|
|
|
<el-button
|
|
|
|
|
type="danger"
|
|
|
|
|
link
|
|
|
|
|
size="small"
|
|
|
|
|
@click="handleUploadRemove"
|
|
|
|
|
class="item-remove"
|
|
|
|
|
>
|
|
|
|
|
<el-icon><Close /></el-icon>
|
|
|
|
|
</el-button>
|
|
|
|
|
<span v-else class="item-title">{{ item.title || item.name || '会议纪要' }}</span>
|
|
|
|
|
<el-button v-if="item.mode === 'oa_meeting_minutes'" type="primary" link size="small" @click="handleViewSelectedDetail(item)">查看详情</el-button>
|
|
|
|
|
<el-button type="primary" link size="small" :disabled="index === 0" @click="moveItem(index, -1)">上移</el-button>
|
|
|
|
|
<el-button type="primary" link size="small" :disabled="index === selectedItems.length - 1" @click="moveItem(index, 1)">下移</el-button>
|
|
|
|
|
<el-button type="danger" link size="small" @click="removeItem(index)" class="item-remove"><el-icon><Close /></el-icon></el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 未选择时的操作区域 -->
|
|
|
|
|
<div v-else class="action-container">
|
|
|
|
|
<div class="action-container">
|
|
|
|
|
<!-- 模式选择 -->
|
|
|
|
|
<el-radio-group v-model="inputMode" class="mode-selector" @change="handleModeChange" size="small">
|
|
|
|
|
<el-radio-button label="oa_meeting_minutes">选择会议纪要</el-radio-button>
|
|
|
|
|
@ -69,7 +36,7 @@
|
|
|
|
|
type="primary"
|
|
|
|
|
size="small"
|
|
|
|
|
@click="showSelectDialog = true"
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
:disabled="disabled || selectedItems.length >= maxItems"
|
|
|
|
|
>
|
|
|
|
|
<el-icon><Document /></el-icon>
|
|
|
|
|
选择
|
|
|
|
|
@ -80,11 +47,9 @@
|
|
|
|
|
:headers="uploadHeaders"
|
|
|
|
|
:on-success="handleUploadSuccess"
|
|
|
|
|
:on-error="handleUploadError"
|
|
|
|
|
:on-remove="handleUploadRemove"
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
:file-list="uploadFileList"
|
|
|
|
|
:limit="1"
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
:file-list="[]"
|
|
|
|
|
:disabled="disabled || selectedItems.length >= maxItems"
|
|
|
|
|
:show-file-list="false"
|
|
|
|
|
>
|
|
|
|
|
<el-button type="primary" size="small" :disabled="disabled">
|
|
|
|
|
@ -98,25 +63,24 @@
|
|
|
|
|
|
|
|
|
|
<!-- 展示态 -->
|
|
|
|
|
<div v-else class="readonly-display">
|
|
|
|
|
<div v-if="titleOnly && displayValue" class="readonly-item readonly-duplicate">
|
|
|
|
|
<span class="readonly-title">{{ duplicateTitle }}</span>
|
|
|
|
|
<span v-if="repeatNotice" class="readonly-repeat-note">{{ repeatNotice }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 关联 OA 会议纪要 -->
|
|
|
|
|
<div v-else-if="displayValue && displayValue.mode === 'oa_meeting_minutes'" class="readonly-item readonly-oa">
|
|
|
|
|
<div v-for="(item, index) in displayItems" :key="getItemKey(item, index)" class="readonly-item" :class="item.mode === 'oa_meeting_minutes' ? 'readonly-oa' : 'readonly-upload'">
|
|
|
|
|
<template v-if="titleOnly || getItemUsage(item, index).isDuplicate">
|
|
|
|
|
<span class="readonly-title">{{ item.title || item.name || '会议纪要' }}</span>
|
|
|
|
|
<span v-if="repeatNotice" class="readonly-repeat-note">{{ repeatNotice }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else-if="item.mode === 'oa_meeting_minutes'">
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
class="readonly-title readonly-title--link"
|
|
|
|
|
@click.prevent="handleViewDetail"
|
|
|
|
|
>
|
|
|
|
|
{{ displayValue.title || '会议纪要' }}
|
|
|
|
|
{{ item.title || '会议纪要' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<div class="readonly-actions">
|
|
|
|
|
<el-link
|
|
|
|
|
v-if="displayValue.file_url"
|
|
|
|
|
:href="displayValue.file_url"
|
|
|
|
|
v-if="item.file_url"
|
|
|
|
|
:href="item.file_url"
|
|
|
|
|
target="_blank"
|
|
|
|
|
type="primary"
|
|
|
|
|
size="small"
|
|
|
|
|
@ -125,15 +89,13 @@
|
|
|
|
|
下载
|
|
|
|
|
</el-link>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 上传的附件 -->
|
|
|
|
|
<div v-else-if="displayValue && displayValue.mode === 'upload'" class="readonly-item readonly-upload">
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else-if="item.mode === 'upload'">
|
|
|
|
|
<el-icon class="readonly-icon"><Paperclip /></el-icon>
|
|
|
|
|
<span class="readonly-title">{{ displayValue.name || '附件' }}</span>
|
|
|
|
|
<span class="readonly-title">{{ item.name || '附件' }}</span>
|
|
|
|
|
<el-link
|
|
|
|
|
v-if="displayValue.url"
|
|
|
|
|
:href="displayValue.url"
|
|
|
|
|
v-if="item.url"
|
|
|
|
|
:href="item.url"
|
|
|
|
|
target="_blank"
|
|
|
|
|
type="primary"
|
|
|
|
|
size="small"
|
|
|
|
|
@ -142,10 +104,11 @@
|
|
|
|
|
<el-icon><Download /></el-icon>
|
|
|
|
|
下载
|
|
|
|
|
</el-link>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 空状态 -->
|
|
|
|
|
<div v-else class="readonly-empty">
|
|
|
|
|
<div v-if="displayItems.length === 0" class="readonly-empty">
|
|
|
|
|
<span class="empty-text">未选择</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -179,11 +142,10 @@
|
|
|
|
|
:data="meetingMinutesList"
|
|
|
|
|
v-loading="loadingMeetingMinutes"
|
|
|
|
|
@expand-change="handleExpandChange"
|
|
|
|
|
@row-click="handleSelectMeetingMinute"
|
|
|
|
|
:row-class-name="getRowClassName"
|
|
|
|
|
highlight-current-row
|
|
|
|
|
@selection-change="handleSelectionChange"
|
|
|
|
|
style="width: 100%; margin-top: 16px"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column type="selection" width="48" />
|
|
|
|
|
<!-- 显眼的展开入口:按钮列(不依赖小三角) -->
|
|
|
|
|
<el-table-column label="详情" width="110" align="center" class-name="expand-action-col">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
@ -344,7 +306,7 @@
|
|
|
|
|
</div>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<el-button @click="showSelectDialog = false">取消</el-button>
|
|
|
|
|
<el-button type="primary" @click="confirmSelect" :disabled="!selectedRow">确定</el-button>
|
|
|
|
|
<el-button type="primary" @click="confirmSelect" :disabled="selectedRows.length === 0">确定</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
@ -484,7 +446,7 @@
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed, watch, onMounted } from 'vue'
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
import { Document, Upload, Download, Paperclip, Search, Close, List } from '@element-plus/icons-vue'
|
|
|
|
|
import { oaMeetingMinutesAPI } from '@/utils/api'
|
|
|
|
|
import { getToken } from '@/utils/auth'
|
|
|
|
|
@ -492,7 +454,7 @@ import config from '@/config'
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
modelValue: {
|
|
|
|
|
type: [Object, String, null],
|
|
|
|
|
type: [Array, Object, String, null],
|
|
|
|
|
default: null
|
|
|
|
|
},
|
|
|
|
|
readonly: {
|
|
|
|
|
@ -514,6 +476,14 @@ const props = defineProps({
|
|
|
|
|
repeatNotice: {
|
|
|
|
|
type: String,
|
|
|
|
|
default: ''
|
|
|
|
|
},
|
|
|
|
|
itemUsageResolver: {
|
|
|
|
|
type: Function,
|
|
|
|
|
default: null
|
|
|
|
|
},
|
|
|
|
|
maxItems: {
|
|
|
|
|
type: Number,
|
|
|
|
|
default: 20
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
@ -527,8 +497,7 @@ const showSelectDialog = ref(false)
|
|
|
|
|
const meetingMinutesList = ref([])
|
|
|
|
|
const loadingMeetingMinutes = ref(false)
|
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
|
const selectedRow = ref(null)
|
|
|
|
|
const selectedMeetingMinute = ref(null)
|
|
|
|
|
const selectedRows = ref([])
|
|
|
|
|
const meetingTableRef = ref(null)
|
|
|
|
|
const pagination = ref({
|
|
|
|
|
currentPage: 1,
|
|
|
|
|
@ -537,7 +506,6 @@ const pagination = ref({
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 上传相关
|
|
|
|
|
const uploadFileList = ref([])
|
|
|
|
|
const uploadAction = computed(() => {
|
|
|
|
|
const baseURL = config.api.baseURL
|
|
|
|
|
return `${baseURL}/upload-file`
|
|
|
|
|
@ -557,28 +525,25 @@ const expandedRowDetails = ref({})
|
|
|
|
|
const expandedRowLoading = ref({})
|
|
|
|
|
|
|
|
|
|
// 显示值(用于 readonly 模式)
|
|
|
|
|
const displayValue = computed(() => {
|
|
|
|
|
if (!props.modelValue) return null
|
|
|
|
|
if (typeof props.modelValue === 'string') {
|
|
|
|
|
// 兼容:字符串可能是 JSON(后端 value_text)
|
|
|
|
|
try {
|
|
|
|
|
const parsed = JSON.parse(props.modelValue)
|
|
|
|
|
if (parsed && typeof parsed === 'object') return parsed
|
|
|
|
|
} catch {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
const normalizeMeetingMinutesValue = (raw) => {
|
|
|
|
|
if (!raw) return []
|
|
|
|
|
if (typeof raw === 'string') {
|
|
|
|
|
try { raw = JSON.parse(raw) } catch { return [] }
|
|
|
|
|
}
|
|
|
|
|
if (typeof props.modelValue === 'object') {
|
|
|
|
|
return props.modelValue
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
})
|
|
|
|
|
if (!Array.isArray(raw)) raw = raw && typeof raw === 'object' ? [raw] : []
|
|
|
|
|
return raw.filter(item => item && typeof item === 'object').map((item, index) => ({ ...item, sort_order: index }))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const duplicateTitle = computed(() => {
|
|
|
|
|
if (!displayValue.value || typeof displayValue.value !== 'object') return '会议纪要'
|
|
|
|
|
return displayValue.value.title || displayValue.value.name || '会议纪要'
|
|
|
|
|
})
|
|
|
|
|
const selectedItems = ref([])
|
|
|
|
|
const displayItems = computed(() => normalizeMeetingMinutesValue(props.modelValue))
|
|
|
|
|
const getItemKey = (item, index) => `${item.mode || 'unknown'}:${item.meeting_minute_id || item.upload_id || index}`
|
|
|
|
|
const getItemUsage = (item, index) => typeof props.itemUsageResolver === 'function'
|
|
|
|
|
? props.itemUsageResolver(item, index)
|
|
|
|
|
: { isDuplicate: false }
|
|
|
|
|
const emitItems = (items) => {
|
|
|
|
|
selectedItems.value = items.map((item, index) => ({ ...item, sort_order: index }))
|
|
|
|
|
emit('update:modelValue', selectedItems.value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 拉取会议纪要详情(不直接绑定到 UI,返回 data)
|
|
|
|
|
const fetchMeetingMinuteDetail = async (id) => {
|
|
|
|
|
@ -610,46 +575,17 @@ const loadMeetingMinuteDetailToDialog = async (id) => {
|
|
|
|
|
|
|
|
|
|
// 初始化:根据 modelValue 设置模式和选中项
|
|
|
|
|
watch(() => props.modelValue, (newVal) => {
|
|
|
|
|
if (!newVal) {
|
|
|
|
|
inputMode.value = 'oa_meeting_minutes'
|
|
|
|
|
selectedMeetingMinute.value = null
|
|
|
|
|
uploadFileList.value = []
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof newVal === 'object') {
|
|
|
|
|
if (newVal.mode === 'oa_meeting_minutes') {
|
|
|
|
|
inputMode.value = 'oa_meeting_minutes'
|
|
|
|
|
selectedMeetingMinute.value = {
|
|
|
|
|
id: newVal.meeting_minute_id,
|
|
|
|
|
title: newVal.title || '会议纪要',
|
|
|
|
|
file_url: newVal.file_url || null
|
|
|
|
|
}
|
|
|
|
|
// 如果有 meeting_minute_id,加载详情用于展示
|
|
|
|
|
if (newVal.meeting_minute_id && props.readonly) {
|
|
|
|
|
loadMeetingMinuteDetailToDialog(newVal.meeting_minute_id)
|
|
|
|
|
}
|
|
|
|
|
} else if (newVal.mode === 'upload') {
|
|
|
|
|
inputMode.value = 'upload'
|
|
|
|
|
if (newVal.upload_id) {
|
|
|
|
|
uploadFileList.value = [{
|
|
|
|
|
name: newVal.name || '附件',
|
|
|
|
|
url: newVal.url,
|
|
|
|
|
uid: Date.now()
|
|
|
|
|
}]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, { immediate: true })
|
|
|
|
|
const items = normalizeMeetingMinutesValue(newVal)
|
|
|
|
|
selectedItems.value = items
|
|
|
|
|
inputMode.value = items[0]?.mode || 'oa_meeting_minutes'
|
|
|
|
|
}, { immediate: true, deep: true })
|
|
|
|
|
|
|
|
|
|
// 模式切换
|
|
|
|
|
const handleModeChange = (mode) => {
|
|
|
|
|
if (mode === 'oa_meeting_minutes') {
|
|
|
|
|
uploadFileList.value = []
|
|
|
|
|
emit('update:modelValue', null)
|
|
|
|
|
} else {
|
|
|
|
|
selectedMeetingMinute.value = null
|
|
|
|
|
emit('update:modelValue', null)
|
|
|
|
|
if (selectedItems.value.length > 0 && selectedItems.value[0].mode !== mode) {
|
|
|
|
|
ElMessageBox.confirm('切换来源会清空已添加的会议纪要,是否继续?', '确认切换', { type: 'warning' })
|
|
|
|
|
.then(() => emitItems([]))
|
|
|
|
|
.catch(() => { inputMode.value = selectedItems.value[0].mode })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -708,18 +644,7 @@ const handleSearch = () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 选择行
|
|
|
|
|
const handleSelectMeetingMinute = (row) => {
|
|
|
|
|
selectedRow.value = row
|
|
|
|
|
// 同步 Element Plus 当前行高亮
|
|
|
|
|
if (meetingTableRef.value && typeof meetingTableRef.value.setCurrentRow === 'function') {
|
|
|
|
|
meetingTableRef.value.setCurrentRow(row)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getRowClassName = ({ row }) => {
|
|
|
|
|
if (selectedRow.value && row && row.id === selectedRow.value.id) return 'row-selected-strong'
|
|
|
|
|
return ''
|
|
|
|
|
}
|
|
|
|
|
const handleSelectionChange = (rows) => { selectedRows.value = rows || [] }
|
|
|
|
|
|
|
|
|
|
const toggleExpandRow = async (row) => {
|
|
|
|
|
if (!meetingTableRef.value || typeof meetingTableRef.value.toggleRowExpansion !== 'function') return
|
|
|
|
|
@ -738,56 +663,49 @@ const toggleExpandRow = async (row) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确认选择
|
|
|
|
|
const confirmSelect = () => {
|
|
|
|
|
if (!selectedRow.value) {
|
|
|
|
|
ElMessage.warning('请选择一条会议纪要')
|
|
|
|
|
const confirmSelect = async () => {
|
|
|
|
|
if (selectedRows.value.length === 0) {
|
|
|
|
|
ElMessage.warning('请至少选择一条会议纪要')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化 selectedMeetingMinute,确保有 file_url 字段
|
|
|
|
|
selectedMeetingMinute.value = {
|
|
|
|
|
...selectedRow.value,
|
|
|
|
|
file_url: null // 初始化为 null,后续如果有附件会更新
|
|
|
|
|
}
|
|
|
|
|
const value = {
|
|
|
|
|
mode: 'oa_meeting_minutes',
|
|
|
|
|
meeting_minute_id: selectedRow.value.id,
|
|
|
|
|
title: selectedRow.value.title
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有附件,添加文件信息
|
|
|
|
|
if (selectedRow.value.files && selectedRow.value.files.length > 0) {
|
|
|
|
|
// 加载详情获取文件信息
|
|
|
|
|
fetchMeetingMinuteDetail(selectedRow.value.id).then((detail) => {
|
|
|
|
|
if (detail && detail.files_details && detail.files_details.length > 0) {
|
|
|
|
|
const file = detail.files_details[0]
|
|
|
|
|
value.file_url = file.url
|
|
|
|
|
value.file_name = file.original_name
|
|
|
|
|
// 同步更新 selectedMeetingMinute,以便立即显示附件链接
|
|
|
|
|
selectedMeetingMinute.value.file_url = file.url
|
|
|
|
|
const existingIds = new Set(selectedItems.value.map(item => item.meeting_minute_id))
|
|
|
|
|
const additions = await Promise.all(selectedRows.value
|
|
|
|
|
.filter(row => !existingIds.has(row.id))
|
|
|
|
|
.map(async (row) => {
|
|
|
|
|
const detail = await fetchMeetingMinuteDetail(row.id)
|
|
|
|
|
const file = detail?.files_details?.[0]
|
|
|
|
|
return {
|
|
|
|
|
mode: 'oa_meeting_minutes',
|
|
|
|
|
meeting_minute_id: row.id,
|
|
|
|
|
title: row.title,
|
|
|
|
|
...(file ? { file_url: file.url, file_name: file.original_name || file.name } : {})
|
|
|
|
|
}
|
|
|
|
|
emit('update:modelValue', value)
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
emit('update:modelValue', value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}))
|
|
|
|
|
const items = [...selectedItems.value, ...additions].slice(0, props.maxItems)
|
|
|
|
|
if (items.length === selectedItems.value.length && additions.length > 0) ElMessage.warning(`最多关联 ${props.maxItems} 条会议纪要`)
|
|
|
|
|
emitItems(items)
|
|
|
|
|
selectedRows.value = []
|
|
|
|
|
showSelectDialog.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清除选择
|
|
|
|
|
const clearSelection = () => {
|
|
|
|
|
selectedMeetingMinute.value = null
|
|
|
|
|
emit('update:modelValue', null)
|
|
|
|
|
const removeItem = (index) => emitItems(selectedItems.value.filter((_, itemIndex) => itemIndex !== index))
|
|
|
|
|
const moveItem = (index, offset) => {
|
|
|
|
|
const targetIndex = index + offset
|
|
|
|
|
if (targetIndex < 0 || targetIndex >= selectedItems.value.length) return
|
|
|
|
|
const items = [...selectedItems.value]
|
|
|
|
|
;[items[index], items[targetIndex]] = [items[targetIndex], items[index]]
|
|
|
|
|
emitItems(items)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查看详情
|
|
|
|
|
const handleViewDetail = async () => {
|
|
|
|
|
if (!displayValue.value || !displayValue.value.meeting_minute_id) return
|
|
|
|
|
const item = displayItems.value[0]
|
|
|
|
|
if (!item?.meeting_minute_id) return
|
|
|
|
|
|
|
|
|
|
showDetailDialog.value = true
|
|
|
|
|
|
|
|
|
|
const detail = await loadMeetingMinuteDetailToDialog(displayValue.value.meeting_minute_id)
|
|
|
|
|
const detail = await loadMeetingMinuteDetailToDialog(item.meeting_minute_id)
|
|
|
|
|
|
|
|
|
|
if (!detail) {
|
|
|
|
|
ElMessage.warning('未获取到会议纪要详情')
|
|
|
|
|
@ -796,8 +714,8 @@ const handleViewDetail = async () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 录入态:查看“已选择”的会议纪要详情
|
|
|
|
|
const handleViewSelectedDetail = async () => {
|
|
|
|
|
const id = selectedMeetingMinute.value?.id
|
|
|
|
|
const handleViewSelectedDetail = async (item) => {
|
|
|
|
|
const id = item?.meeting_minute_id
|
|
|
|
|
if (!id) return
|
|
|
|
|
showDetailDialog.value = true
|
|
|
|
|
const detail = await loadMeetingMinuteDetailToDialog(id)
|
|
|
|
|
@ -897,15 +815,22 @@ const handleUploadSuccess = (response) => {
|
|
|
|
|
url: response.data?.url || response.data?.path || response.data,
|
|
|
|
|
uid: Date.now() + Math.random()
|
|
|
|
|
}
|
|
|
|
|
uploadFileList.value = [fileInfo]
|
|
|
|
|
|
|
|
|
|
const value = {
|
|
|
|
|
mode: 'upload',
|
|
|
|
|
upload_id: response.data?.id || response.data?.id,
|
|
|
|
|
upload_id: response.data?.id,
|
|
|
|
|
name: fileInfo.name,
|
|
|
|
|
url: fileInfo.url
|
|
|
|
|
}
|
|
|
|
|
emit('update:modelValue', value)
|
|
|
|
|
const existingIds = new Set(selectedItems.value.map(item => item.upload_id))
|
|
|
|
|
if (existingIds.has(value.upload_id)) {
|
|
|
|
|
ElMessage.warning('该附件已添加')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (selectedItems.value.length >= props.maxItems) {
|
|
|
|
|
ElMessage.warning(`最多关联 ${props.maxItems} 条会议纪要`)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
emitItems([...selectedItems.value, value])
|
|
|
|
|
ElMessage.success('上传成功')
|
|
|
|
|
} else {
|
|
|
|
|
ElMessage.error('上传失败:' + (response.msg || '未知错误'))
|
|
|
|
|
@ -919,11 +844,6 @@ const handleUploadError = (error) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 移除文件
|
|
|
|
|
const handleUploadRemove = () => {
|
|
|
|
|
uploadFileList.value = []
|
|
|
|
|
emit('update:modelValue', null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 打开选择对话框时加载列表
|
|
|
|
|
watch(showSelectDialog, (visible) => {
|
|
|
|
|
if (visible) {
|
|
|
|
|
@ -944,6 +864,13 @@ watch(showSelectDialog, (visible) => {
|
|
|
|
|
/* 已选择/已上传的展示 */
|
|
|
|
|
.selected-display {
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.selected-display + .action-container {
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.selected-item {
|
|
|
|
|
|