Files
guoju0808/ry-vue3/src/views/portal/Invitation.vue
T
2026-10-08 14:07:27 +00:00

207 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="portal-invitation">
<h1 class="page-title">邀请函</h1>
<p class="page-sub">查看项目邀请函(含模板、QR、分享链接)</p>
<el-form inline :model="q" class="filter-bar" @keyup.enter="onSearch">
<el-form-item label="项目编号:">
<el-input v-model="q.projectNo" placeholder="输入项目编号" clearable />
</el-form-item>
<el-form-item label="项目名称:">
<el-input v-model="q.title" placeholder="输入标题" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearch">查询</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
<div class="page-card">
<el-table :data="rows" v-loading="loading" stripe border>
<el-table-column prop="title" label="邀请函标题" min-width="260" show-overflow-tooltip />
<el-table-column prop="projectNo" label="项目编号" width="160" />
<el-table-column prop="publishTime" label="发布时间" width="180">
<template #default="{ row }">{{ fmt(row.publishTime) }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
<el-table-column label="操作" width="320" fixed="right">
<template #default="{ row }"><div class="table-actions">
<el-link :underline="false" type="primary" @click="openDetail(row)">详情</el-link>
<el-link :underline="false" type="primary" :disabled="!row.templateUrl" @click="openPreview(row, 'template')">模板</el-link>
<el-link :underline="false" type="primary" :disabled="!row.qrCodeUrl" @click="openPreview(row, 'qr')">QR</el-link>
<el-link :underline="false" type="primary" :disabled="!row.shareUrl" @click="openPreview(row, 'share')">分享</el-link>
</div></template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="page.pageNum" v-model:page-size="page.pageSize"
:total="page.total" :page-sizes="[10,20,50]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="load" @size-change="load"
style="margin-top: 12px; text-align: right;" />
</div>
<!-- 详情 dialog -->
<el-dialog v-model="detailOpen" title="邀请函详情" width="640" top="6vh">
<el-descriptions v-if="current" :column="1" border>
<el-descriptions-item label="标题">{{ current.title }}</el-descriptions-item>
<el-descriptions-item label="项目编号">{{ current.projectNo }}</el-descriptions-item>
<el-descriptions-item label="发布时间">{{ fmt(current.publishTime) }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ current.remark || '-' }}</el-descriptions-item>
<el-descriptions-item label="模板链接">
<el-link v-if="current.templateUrl" type="primary" @click="openPreview(current, 'template')">点击预览</el-link>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="QR 码">
<el-link v-if="current.qrCodeUrl" type="primary" @click="openPreview(current, 'qr')">点击预览</el-link>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="分享链接">
<el-link v-if="current.shareUrl" type="primary" @click="openPreview(current, 'share')">点击预览</el-link>
<span v-else>-</span>
</el-descriptions-item>
</el-descriptions>
</el-dialog>
<!-- 预览组件 -->
<Preview v-model="previewOpen" :url="previewUrl" :title="previewTitle" />
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { bizList } from '@/api/public'
import Preview from '@/components/Preview.vue'
const q = ref({ projectNo: '', title: '' })
const rows = ref([])
const loading = ref(false)
const page = reactive({ pageNum: 1, pageSize: 20, total: 0 })
async function load() {
loading.value = true
try {
const { data } = await bizList('invitation', { ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
rows.value = data?.rows || []
page.total = data?.total || 0
} catch (e) { rows.value = []; page.total = 0 }
finally { loading.value = false }
}
function onSearch() { page.pageNum = 1; load() }
function onReset() { q.value = { projectNo: '', title: '' }; onSearch() }
// 只显示年月日, 不显示时分秒 (与 portal/Publicity.vue fmtDate 口径一致)
function fmt(t) {
if (!t) return ''
const d = new Date(t)
const p = n => String(n).padStart(2, '0')
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`
}
const detailOpen = ref(false)
const current = ref(null)
function openDetail(row) { current.value = row; detailOpen.value = true }
const previewOpen = ref(false)
const previewUrl = ref('')
const previewTitle = ref('预览')
function openPreview(row, kind) {
if (kind === 'template') { previewUrl.value = row.templateUrl; previewTitle.value = '邀请函模板' }
else if (kind === 'qr') { previewUrl.value = row.qrCodeUrl; previewTitle.value = 'QR 码' }
else if (kind === 'share') { previewUrl.value = row.shareUrl; previewTitle.value = '分享链接' }
previewOpen.value = true
}
load()
</script>
<style scoped>
.portal-invitation { padding: 16px; }
.page-title { font-size: 20px; font-weight: 600; margin: 0 0 8px; }
.page-sub { color: #909399; font-size: 13px; margin: 0 0 16px; }
.filter-bar { background: #fff; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; margin-bottom: 12px; }
.page-card { background: #fff; padding: 16px; border-radius: 6px; border: 1px solid #f0f0f0; }
/* ========================================
移动端适配 (≤768px)
- 卡片 padding 收窄
- 工具栏横向滚动
- filter-form: label 与输入框横向
- 表格字号收紧
======================================== */
@media (max-width: 768px) {
/* 卡片 padding */
.page-card { 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;
}
/* filter-form: 横向 (label 左 + input 右) */
.filter-form {
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;
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;
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) {
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; }
}
</style>