批量推送代码

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
郭庆泰
2026-08-29 17:52:05 +08:00
co-authored by Claude
parent 36528b6e0c
commit e47f76478b
130 changed files with 3972 additions and 2546 deletions
+1 -1
View File
@@ -244,7 +244,7 @@ async function loadUserProfile() {
}
onMounted(async () => {
form.name = store.user?.userName || ''
form.name = store.user?.nickName || ''
form.phone = store.user?.phonenumber || ''
await Promise.all([loadUserProfile(), loadExpertProfile()])
snapshot = ref(JSON.parse(JSON.stringify(form)))
+26 -60
View File
@@ -14,44 +14,27 @@
</div>
</div>
<!-- 参加的会议 + 签署的协议: 仅审核通过的医生可见 -->
<div class="cols-row" v-if="store.expertAuditApproved">
<div class="section">
<h2 class="section-title">
待参加的会议
<a class="more" @click.prevent="$router.push('/doctor/meetings')">更多 </a>
</h2>
<ul class="simple-list">
<li class="simple-item" v-for="m in upcomingMeetings" :key="m.meetingId" @click="$router.push('/doctor/meetings')">
<div class="item-main">
<span class="item-title">{{ m.meetingName || m.title }}</span>
</div>
<span class="item-status">{{ formatTime(m.startTime) }}</span>
</li>
<li v-if="!upcomingMeetings.length" class="empty">暂无待参加会议</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">
待签署的协议
<a class="more" @click.prevent="$router.push('/doctor/submissions')">更多 </a>
</h2>
<ul class="simple-list">
<li
class="simple-item"
:class="{ disabled: s.isEsigned !== 1 }"
v-for="(s, idx) in pendingAgreements"
:key="s.id"
@click="s.isEsigned === 1 && showQrcode(s, idx)"
>
<div class="item-main">
<span class="item-title">{{ s.meetingName || ('会议 #' + s.meetingId) }}</span>
</div>
<span class="item-status">{{ s.isEsigned === 1 ? '待签署' : '未推送' }}</span>
</li>
<li v-if="!pendingAgreements.length" class="empty">暂无待签协议</li>
</ul>
</div>
<!-- 待签署的协议: 仅审核通过的医生可见 -->
<div class="section" v-if="store.expertAuditApproved">
<h2 class="section-title">
待签署的协议
<a class="more" @click.prevent="$router.push('/doctor/submissions')">更多 </a>
</h2>
<ul class="simple-list">
<li
class="simple-item"
:class="{ disabled: s.isEsigned !== 1 }"
v-for="(s, idx) in pendingAgreements"
:key="s.id"
@click="s.isEsigned === 1 && showQrcode(s, idx)"
>
<div class="item-main">
<span class="item-title">{{ s.meetingName || ('会议 #' + s.meetingId) }}</span>
</div>
<span class="item-status">{{ s.isEsigned === 1 ? '待签署' : '未推送' }}</span>
</li>
<li v-if="!pendingAgreements.length" class="empty">暂无待签协议</li>
</ul>
</div>
<!-- 通知消息 (NoticeList 组件内部已含 SSE 实时刷新 + 详情 dialog + 全部已读) -->
@@ -60,7 +43,7 @@
通知消息
<a class="more" @click.prevent="$router.push('/doctor/messages')">更多 </a>
</h2>
<NoticeList :limit="5" :show-header="false" />
<NoticeList :pageable="true" :show-header="false" />
</section>
<!-- 二维码弹窗 -->
@@ -87,18 +70,17 @@ import { useUserStore } from '@/store/user'
import { ElMessage } from 'element-plus'
import QRCode from 'qrcode'
import { getMyExpertProfile } from '@/api/business/expert'
import { listUnsignedMeetingProtocols, listInvitedMeetings } from '@/api/business/meetingAttendee'
import { listUnsignedMeetingProtocols } from '@/api/business/meetingAttendee'
import NoticeList from '@/components/NoticeList.vue'
const store = useUserStore()
const upcomingMeetings = ref([])
const pendingAgreements = ref([])
// 专家真实姓名 (从 biz_expert.name 拿, 不显示 sys_user.userName (登录账号/手机号))
const expertName = ref('')
// 兜底显示名: 优先专家真实姓名 > nickName > userName > '专家'
const displayName = computed(() =>
expertName.value || store.user?.nickName || store.user?.userName || '专家'
expertName.value || store.user?.nickName || '专家'
)
const nowTime = ref('')
@@ -154,16 +136,6 @@ async function copyQrcodeUrl() {
}
}
function formatTime(t) {
if (!t) return ''
const d = new Date(t)
const today = new Date()
const diff = Math.floor((d - today) / 86400000)
if (diff === 0) return d.toTimeString().slice(0, 5)
if (diff === 1) return '明天'
return `${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
}
function updateClock() {
const now = new Date()
nowTime.value = now.toTimeString().slice(0, 5)
@@ -177,13 +149,8 @@ async function load() {
expertName.value = data?.name || ''
} catch (e) { expertName.value = '' }
// 待参加会议 + 待签署协议: 仅审核通过的医生才拉 (未通过时 2 个 pannel 隐藏)
// 待签署协议: 仅审核通过的医生才拉 (未通过时 panel 隐藏)
if (store.expertAuditApproved) {
try {
const { data } = await listInvitedMeetings()
upcomingMeetings.value = (Array.isArray(data) ? data : []).slice(0, 5)
} catch (e) { upcomingMeetings.value = [] }
try {
const { data } = await listUnsignedMeetingProtocols()
pendingAgreements.value = (data || []).slice(0, 5).map(s => ({
@@ -195,7 +162,6 @@ async function load() {
}))
} catch (e) { pendingAgreements.value = [] }
} else {
upcomingMeetings.value = []
pendingAgreements.value = []
}
// 通知列表已抽到 <NoticeList> 组件, 本页不再处理
@@ -215,7 +181,7 @@ onBeforeUnmount(() => {
.doctor-home { padding: 16px 20px; }
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
.welcome-bar { background: var(--brand-primary); border-radius: 4px; padding: 20px 24px; color: #fff; display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.welcome-text h2 { font-size: 20px; font-weight: 600; margin-bottom: 6px; }
.welcome-text h2 { font-size: 20px; font-weight: 600; margin-bottom: 6px; color: #fff; }
.welcome-text p { font-size: 13px; opacity: 0.85; }
.welcome-time .now { font-size: 14px; font-weight: 500; }
.welcome-time .date { font-size: 12px; opacity: 0.75; margin-top: 4px; }
+13 -5
View File
@@ -10,7 +10,7 @@
<el-option v-for="o in STAGE_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
</el-select>
</el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
</el-form>
<el-table :data="rows" v-loading="loading" stripe border>
@@ -23,12 +23,20 @@
</el-table-column>
<el-table-column label="日程" width="130" align="center">
<template #default="{ row }">
<el-link :underline="false" type="primary" :disabled="!row.scheduleUrl" @click="onPreview(row.scheduleUrl, '日程海报')">查看</el-link>
<el-link :underline="false" :disabled="!row.scheduleUrl" @click="onDownload(row.scheduleUrl, `${row.meetingName || '会议'}_日程海报`)">下载</el-link></template></el-table-column>
<div class="table-actions">
<el-link :underline="false" type="primary" :disabled="!row.scheduleUrl" @click="onPreview(row.scheduleUrl, '日程海报')">查看</el-link>
<el-link :underline="false" :disabled="!row.scheduleUrl" @click="onDownload(row.scheduleUrl, `${row.meetingName || '会议'}_日程海报`)">下载</el-link>
</div>
</template>
</el-table-column>
<el-table-column label="邀请函" width="130" align="center">
<template #default="{ row }">
<el-link :underline="false" type="primary" :disabled="!row.projectInvitationUrl" @click="onPreview(row.projectInvitationUrl, '邀请函')">查看</el-link>
<el-link :underline="false" :disabled="!row.projectInvitationUrl" @click="onDownload(row.projectInvitationUrl, `${row.meetingName || '会议'}_邀请函`)">下载</el-link></template></el-table-column>
<div class="table-actions">
<el-link :underline="false" type="primary" :disabled="!row.projectInvitationUrl" @click="onPreview(row.projectInvitationUrl, '邀请函')">查看</el-link>
<el-link :underline="false" :disabled="!row.projectInvitationUrl" @click="onDownload(row.projectInvitationUrl, `${row.meetingName || '会议'}_邀请函`)">下载</el-link>
</div>
</template>
</el-table-column>
<el-table-column label="签署状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.attendeeLaborProtocol ? 'success' : 'info'" size="small">{{ row.attendeeLaborProtocol ? '已签署' : '未签署' }}</el-tag>
+11 -3
View File
@@ -6,13 +6,21 @@
<el-form-item label="项目编号"><el-input v-model="q.projectNo" placeholder="输入项目编号" clearable /></el-form-item>
<el-form-item label="项目名称"><el-input v-model="q.projectName" placeholder="输入项目名称" clearable /></el-form-item>
<el-form-item label="会议名称"><el-input v-model="q.meetingName" placeholder="输入会议名称" clearable /></el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
</el-form>
<el-table :data="rows" v-loading="loading" stripe border>
<el-table-column prop="projectNo" label="项目编号" width="170" />
<el-table-column prop="projectName" label="项目名称" min-width="240" show-overflow-tooltip />
<el-table-column prop="meetingName" label="会议名称" min-width="220" show-overflow-tooltip />
<el-table-column prop="projectName" label="项目名称" min-width="240" show-overflow-tooltip>
<template #default="{ row }">
<el-link :underline="false" type="primary" @click="onView(row)">{{ row.projectName }}</el-link>
</template>
</el-table-column>
<el-table-column prop="meetingName" label="会议名称" min-width="220" show-overflow-tooltip>
<template #default="{ row }">
<el-link :underline="false" type="primary" @click="onView(row)">{{ row.meetingName }}</el-link>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<span class="status">{{ row.status || '已报名' }}</span>
+58 -3
View File
@@ -5,7 +5,20 @@
<el-button type="primary" @click="goBack">返回</el-button>
</div>
<div v-else v-loading="loading">
<el-form :model="form" :rules="rules" ref="formRef" label-position="top" class="sign-fill-form">
<!-- 已签署: 再次打开签署链接, 直接展示劳务协议 PDF (复用 publicity OSS 代理预览) -->
<div v-if="signed" class="signed-pdf">
<div class="sign-header">
<div class="sign-header-title">{{ meetingName || '劳务协议' }}</div>
<div v-if="periodDisplay" class="sign-header-period">期数{{ periodDisplay }}</div>
</div>
<iframe v-if="laborPdfUrl" :src="proxyUrl(laborPdfUrl)" class="signed-pdf-frame"></iframe>
<div v-else class="signed-pdf-empty">协议已签署暂无可展示的 PDF</div>
<div class="signed-pdf-actions">
<el-button v-if="laborPdfUrl" type="primary" @click="downloadPdf">下载劳务协议</el-button>
<el-button @click="goBack">返回</el-button>
</div>
</div>
<el-form v-else :model="form" :rules="rules" ref="formRef" label-position="top" class="sign-fill-form">
<!-- 大标题: 会议名称 + 期数 -->
<div class="sign-header">
<div class="sign-header-title">{{ meetingName || '劳务协议签署' }}</div>
@@ -106,6 +119,9 @@ const notInvited = ref(false)
const loading = ref(false)
const submitting = ref(false)
const formRef = ref(null)
// 已签署状态: 再次打开签署链接时直接展示 PDF
const signed = ref(false)
const laborPdfUrl = ref('')
// 劳务形式 (checkboxOther 多选)
const laborFormOptions = ref([])
@@ -173,7 +189,7 @@ async function ensureLogin() {
userStore.setUser({
userId: u.userId,
userName: u.userName || u.nickName || '',
nickName: u.nickName || u.userName || '',
nickName: u.nickName || '',
phonenumber: u.phonenumber || '',
accountType: u.accountType || 'MAIN',
parentUserId: u.parentUserId || null,
@@ -231,6 +247,21 @@ async function load() {
loading.value = true
try {
const { data } = await getSignInfo(attendeeId.value)
// 已签署: 再次打开签署链接 → 整页跳转到 OSS proxy 的 PDF 地址 (全屏显示, 不用 iframe 内嵌)
if (data.signed || (data.laborProtocol && data.laborProtocol.trim())) {
const url = data.laborProtocol
if (url) {
window.location.href = proxyUrl(url)
return
}
// 无 PDF URL 兜底: 仍留在本页显示"已签署但无可展示 PDF"
signed.value = true
laborPdfUrl.value = ''
meetingName.value = data.meetingName || ''
periodNo.value = data.periodNo ?? null
totalPeriods.value = data.totalPeriods ?? null
return
}
// 预填 (current 优先, 否则用 defaults)
const cur = data.current || {}
const def = data.defaults || {}
@@ -326,6 +357,23 @@ async function onSubmit() {
}
}
// OSS 代理预览 (同 publicity / doctor/Meetings.vue): 重写 Content-Disposition 为 inline, 隐藏工具栏撑满宽度
function proxyUrl(url) {
if (!url) return url
if (url.includes('hwtossbamlorgcn.oss-cn-beijing.aliyuncs.com')) {
return import.meta.env.VITE_APP_BASE_API + '/common/oss/proxy?url=' + encodeURIComponent(url) + '#toolbar=0&zoom=page-width'
}
return url
}
function downloadPdf() {
if (!laborPdfUrl.value) return
const a = document.createElement('a')
a.href = laborPdfUrl.value
a.download = `${meetingName.value || '劳务协议'}.pdf`
a.target = '_blank'
document.body.appendChild(a); a.click(); document.body.removeChild(a)
}
function goBack() {
router.push('/doctor/home')
}
@@ -335,13 +383,20 @@ onMounted(init)
<style scoped>
/* 手机端全屏表单 (无 navbar / 无 page-card) */
.sign-fill { padding: 16px; }
.sign-fill { padding: 0; }
.sign-fill-form { padding: 16px; }
/* 大标题: 会议名称 + 期数 */
.sign-header { margin: 4px 0 20px; padding-bottom: 14px; border-bottom: 1px solid #f0f0f0; }
.sign-header-title { font-size: 20px; font-weight: 600; color: #1a1a1a; line-height: 1.4; }
.sign-header-period { margin-top: 6px; font-size: 14px; color: #595959; }
/* 已签署: 直接展示 PDF (宽度 100%, 高度不限制) */
.signed-pdf { display: flex; flex-direction: column; }
.signed-pdf-frame { width: 100%; height: 424vw; border: 0; }
.signed-pdf-empty { padding: 48px 16px; text-align: center; color: #909399; }
.signed-pdf-actions { margin-top: 16px; display: flex; gap: 12px; }
/* 未受邀提示 */
.not-invited { padding: 60px 20px; text-align: center; }
.not-invited-text { font-size: 16px; color: #606266; margin-bottom: 20px; }
+54 -64
View File
@@ -115,9 +115,12 @@ onMounted(load)
</script>
<style scoped>
/* 整页面板 (详情页标准: max-width 1200px) */
.doctor-submission-detail { max-width: 1200px; padding: 16px; }
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 20px; }
/* 整页面板 (与 Submissions.vue 列表页风格一致: 16px/20px padding, 6px 圆角, 1px 浅灰描边) */
.doctor-submission-detail { background: #fff; max-width: 1200px; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; }
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
/* 主按钮品牌色 (与列表页保持一致) */
:deep(.el-button--primary) { background: var(--brand-primary); border-color: var(--brand-primary); border-radius: 4px; }
:deep(.el-button--primary:hover) { background: var(--brand-primary-deep); border-color: var(--brand-primary-deep); }
/* 只读表单样式 - 模拟 el-input 视觉, 但只显示文字 */
.readonly-form :deep(.el-form-item) { margin-bottom: 22px; }
@@ -140,84 +143,71 @@ onMounted(load)
/* ========================================
移动端适配 (≤768px)
- 卡片 padding 收窄
- 工具栏横向滚动
- filter-form: label 与输入框横向
- 表格字号收紧
移动端适配 (≤768px) — 参考 executor/meetings/new MeetingNew.vue
不动 el-form-item__label 内部样式 (float/width/height), 只改容器布局,
让 Element Plus 自带的 label-width=120px 右对齐 + input 高度自然撑开 label
======================================== */
@media (max-width: 768px) {
/* 卡片 padding */
.page-card { padding: 12px !important; border-radius: 4px !important; }
/* 卡片 padding (与列表页统一) */
.doctor-submission-detail { padding: 12px !important; border-radius: 4px !important; }
.breadcrumb { font-size: 12px !important; margin-bottom: 8px !important; }
/* 工具栏: 横向滚动 */
.toolbar {
flex-wrap: nowrap !important;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 6px;
margin-bottom: 8px !important;
scrollbar-width: thin;
/* 双列 → 单列:
- el-row 强制 block (避免 flex 横排)
- el-col 强制 100% 宽
间距来源: 桌面样式 .readonly-form :deep(.el-form-item) { margin-bottom: 22px }
(第 126 行), 手机端直接继承, 不再额外加 padding 避免双倍间距 */
.readonly-form :deep(.el-row) {
display: block !important;
}
.toolbar::-webkit-scrollbar { height: 4px; }
.toolbar::-webkit-scrollbar-thumb { background: var(--brand-slate-200); border-radius: 2px; }
.toolbar :deep(.action-btn),
.toolbar :deep(.el-button) {
flex-shrink: 0;
font-size: 12px !important;
padding: 0 10px !important;
height: 30px !important;
.readonly-form :deep(.el-col) {
width: 100% !important;
max-width: 100% !important;
flex: 0 0 100% !important;
display: block !important;
}
/* filter-form: 横向 (label 左 + input 右) */
.filter-form {
/* form-item: 横向 label + content, flex-start 让 error message 占独立行
保留桌面已有的 22px margin-bottom (不要清零, 那是行间/字段间间距的关键),
改 flex-start 避免多行 label 被居中.
不动 __label 的 float/width/height/line-height — Element Plus 自带 label-width=120px
会自然右对齐 + 跟随 content 行高, 不会参差不齐 */
.readonly-form :deep(.el-form-item) {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
gap: 10px !important;
}
.filter-form :deep(.el-form-item) {
display: flex !important;
align-items: center !important;
align-items: flex-start !important;
margin-right: 0 !important;
margin-bottom: 0 !important;
}
.filter-form :deep(.el-form-item__label) {
float: none !important;
width: auto !important;
min-width: 80px !important;
text-align: right !important;
padding: 0 8px 0 0 !important;
font-size: 13px !important;
color: var(--el-text-color-regular) !important;
line-height: 32px !important;
height: 32px !important;
}
.filter-form :deep(.el-form-item__content) {
margin-left: 0 !important;
line-height: 32px !important;
.readonly-form :deep(.el-form-item__content) {
flex: 1 !important;
min-width: 0 !important;
}
/* 强制所有控件全宽 */
.filter-form :deep(.el-select),
.filter-form :deep(.el-input),
.filter-form :deep(.el-date-editor),
.filter-form :deep(.el-button),
.filter-form :deep(.el-cascader) {
/* 只读控件全宽, display:block 让 textarea 也按 block 拉伸 */
.readonly-form :deep(.el-input),
.readonly-form :deep(.el-textarea) {
width: 100% !important;
min-width: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
display: block !important;
}
.filter-form :deep(.el-button + .el-button) {
margin-top: 8px !important;
}
.readonly-cell { flex: 1; min-width: 0; font-size: 14px; }
/* 表格字号收紧 */
:deep(.el-table) { font-size: 12px !important; }
/* 返回按钮 — 左右并排 (与 MeetingNew 的 form-actions 一致) */
.detail-actions {
display: flex !important;
flex-wrap: wrap !important;
gap: 0 !important;
margin-top: 16px !important;
padding-top: 16px !important;
border-top: 1px solid #f0f0f0;
}
.detail-actions :deep(.el-button) {
flex: 1 1 0 !important;
width: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
.detail-actions :deep(.el-button + .el-button) {
margin-left: 8px !important;
}
}
</style>
</style>
+50 -66
View File
@@ -60,12 +60,13 @@
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" :loading="saving" @click="onSave">保存</el-button>
<el-button @click="confirmCancel">取消</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 el-form 提出来, 避免 Element Plus form-item 容器影响按钮布局 -->
<div class="detail-actions">
<el-button type="primary" :loading="saving" @click="onSave">保存</el-button>
<el-button @click="confirmCancel">取消</el-button>
</div>
</div>
</template>
@@ -198,90 +199,73 @@ onMounted(() => {
</script>
<style scoped>
/* 整页面板 (与 admin/ExpertNew.vue 一致: max-width 1200px) */
.doctor-submission-new { max-width: 1200px; padding: 16px; }
/* 整页面板 (与 Submissions.vue 列表页风格一致) */
.doctor-submission-new { background: #fff; max-width: 1200px; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; }
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
/* 主按钮品牌色 (与列表页保持一致) */
:deep(.el-button--primary) { background: var(--brand-primary); border-color: var(--brand-primary); border-radius: 4px; }
:deep(.el-button--primary:hover) { background: var(--brand-primary-deep); border-color: var(--brand-primary-deep); }
/* 操作按钮区 (从 el-form 提出来, 桌面/移动端一致布局) */
.detail-actions { display: flex; gap: 8px; margin-top: 16px; padding-top: 16px; border-top: 1px solid #f0f0f0; }
/* ========================================
移动端适配 (≤768px)
- 卡片 padding 收窄
- 工具栏横向滚动
- filter-form: label 与输入框横向
- 表格字号收紧
移动端适配 (≤768px) — 参考 executor/meetings/new MeetingNew
不动 el-form-item__label 内部样式 (float/width/height), 让 Element Plus 自带
label-width=120px 右对齐 + input 高度自然撑开 label, 不会参差不齐
======================================== */
@media (max-width: 768px) {
/* 卡片 padding */
.page-card { padding: 12px !important; border-radius: 4px !important; }
/* 卡片 padding (与列表页统一) */
.doctor-submission-new { padding: 12px !important; border-radius: 4px !important; }
.breadcrumb { font-size: 12px !important; margin-bottom: 8px !important; }
/* 工具栏: 横向滚动 */
.toolbar {
flex-wrap: nowrap !important;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 6px;
margin-bottom: 8px !important;
scrollbar-width: thin;
}
.toolbar::-webkit-scrollbar { height: 4px; }
.toolbar::-webkit-scrollbar-thumb { background: var(--brand-slate-200); border-radius: 2px; }
.toolbar :deep(.action-btn),
.toolbar :deep(.el-button) {
flex-shrink: 0;
font-size: 12px !important;
padding: 0 10px !important;
height: 30px !important;
/* 双列 → 单列: el-row 强制 block, el-col 100% 宽 */
.doctor-submission-new :deep(.el-row) { display: block !important; }
.doctor-submission-new :deep(.el-col) {
width: 100% !important;
max-width: 100% !important;
flex: 0 0 100% !important;
display: block !important;
}
/* filter-form: 横向 (label 左 + input 右) */
.filter-form {
/* form-item: 横向 label + content, flex-start 让 error message 占独立行
不动 __label 的 float/width/height/line-height,
不动 form-item 的 margin-bottom (桌面默认 0, 手机端继承, 间距靠 el-form-item 自带 + el-row 默认布局) */
.doctor-submission-new :deep(.el-form-item) {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
gap: 10px !important;
}
.filter-form :deep(.el-form-item) {
display: flex !important;
align-items: center !important;
align-items: flex-start !important;
margin-right: 0 !important;
margin-bottom: 0 !important;
}
.filter-form :deep(.el-form-item__label) {
float: none !important;
width: auto !important;
min-width: 80px !important;
text-align: right !important;
padding: 0 8px 0 0 !important;
font-size: 13px !important;
color: var(--el-text-color-regular) !important;
line-height: 32px !important;
height: 32px !important;
}
.filter-form :deep(.el-form-item__content) {
margin-left: 0 !important;
line-height: 32px !important;
.doctor-submission-new :deep(.el-form-item__content) {
flex: 1 !important;
min-width: 0 !important;
}
/* 强制所有控件全宽 */
.filter-form :deep(.el-select),
.filter-form :deep(.el-input),
.filter-form :deep(.el-date-editor),
.filter-form :deep(.el-button),
.filter-form :deep(.el-cascader) {
/* 全部控件全宽, display:block 强制 select/input 也按 block 拉伸 (与列表页一致) */
.doctor-submission-new :deep(.el-select),
.doctor-submission-new :deep(.el-input),
.doctor-submission-new :deep(.el-textarea),
.doctor-submission-new :deep(.el-date-editor),
.doctor-submission-new :deep(.el-cascader) {
width: 100% !important;
min-width: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
display: block !important;
}
.filter-form :deep(.el-button + .el-button) {
margin-top: 8px !important;
}
/* 表格字号收紧 */
:deep(.el-table) { font-size: 12px !important; }
/* 保存/取消按钮 — 独立 .detail-actions, flex 横排占满 */
.detail-actions {
display: flex !important;
gap: 8px !important;
margin-top: 16px !important;
padding-top: 16px !important;
border-top: 1px solid #f0f0f0;
}
.detail-actions :deep(.el-button) {
flex: 1 1 0 !important;
width: 0 !important;
}
}
</style>
+20 -4
View File
@@ -22,14 +22,14 @@
</el-form-item>
<el-form-item label="状态">
<el-select v-model="q.status" placeholder="请选择" clearable style="width: 140px">
<el-option label="提交" value="0" />
<el-option label="提交" value="0" />
<el-option label="待审核" value="1" />
<el-option label="通过" value="2" />
<el-option label="拒绝" value="3" />
</el-select>
</el-form-item>
<el-form-item label="备注"><el-input v-model="q.remark" placeholder="输入备注" clearable style="width: 200px" /></el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
<el-form-item><el-button type="primary" @click="load"></el-button><el-button @click="reset">重置</el-button></el-form-item>
</el-form>
<div class="toolbar">
@@ -48,8 +48,10 @@
<el-table-column label="设计文件" width="140">
<template #default="{ row }">
<template v-if="row.designFileUrl">
<el-link :underline="false" type="primary" @click="openPreview(row.designFileUrl, '设计文件')">查看</el-link>
<el-link type="primary" :href="row.designFileUrl" target="_blank">下载</el-link>
<div class="table-actions">
<el-link :underline="false" type="primary" @click="openPreview(row.designFileUrl, '设计文件')">查看</el-link>
<el-link type="primary" :href="row.designFileUrl" target="_blank">下载</el-link>
</div>
</template>
<span v-else>-</span>
</template>
@@ -59,6 +61,20 @@
<audit-status-tag :status="row.status" />
</template>
</el-table-column>
<el-table-column label="是否结算" width="100" align="center">
<template #default="{ row }">
<el-tag size="small" :type="row.isSettled==='Y' ? 'success' : 'warning'">
{{ row.isSettled==='Y' ? '已结算' : '未结算' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="projectNo" label="项目编号" width="140" align="center" />
<el-table-column label="创建时间" width="160" align="center">
<template #default="{ row }">{{ row.createTime || '-' }}</template>
</el-table-column>
<el-table-column label="审核意见" min-width="180" show-overflow-tooltip>
<template #default="{ row }">{{ row.auditOpinion || '-' }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
<el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }"><div class="table-actions">