Compare commits
4 Commits
11ae08dc96
...
52beb9b264
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52beb9b264 | ||
|
|
2d9a83d68e | ||
|
|
5cf79a3f7e | ||
|
|
67ac563ddb |
@ -448,6 +448,16 @@ export default {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册时间筛选(日期范围)
|
||||||
|
if (params.created_at && Array.isArray(params.created_at) && params.created_at.length === 2) {
|
||||||
|
const [startTime, endTime] = params.created_at
|
||||||
|
filteredUsers = filteredUsers.filter(user => {
|
||||||
|
if (!user.created_at) return false
|
||||||
|
const userTime = new Date(user.created_at).getTime()
|
||||||
|
return userTime >= startTime && userTime <= endTime
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 分页处理
|
// 分页处理
|
||||||
const page = Number(params.page) || 1
|
const page = Number(params.page) || 1
|
||||||
const pageSize = Number(params.page_size) || 10
|
const pageSize = Number(params.page_size) || 10
|
||||||
|
|||||||
@ -135,6 +135,7 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
v-model:value="formData.email"
|
v-model:value="formData.email"
|
||||||
placeholder="请输入邮箱地址"
|
placeholder="请输入邮箱地址"
|
||||||
clearable
|
clearable
|
||||||
|
:disabled="mode === 'view'"
|
||||||
/>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
|
||||||
@ -145,6 +146,7 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
placeholder="请输入文案内容"
|
placeholder="请输入文案内容"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
clearable
|
clearable
|
||||||
|
:disabled="mode === 'view'"
|
||||||
/>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
|
||||||
@ -158,6 +160,7 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
@change="handleUploadChange"
|
@change="handleUploadChange"
|
||||||
@remove="handleRemove"
|
@remove="handleRemove"
|
||||||
|
:disabled="mode === 'view'"
|
||||||
>
|
>
|
||||||
<div class="upload-trigger">
|
<div class="upload-trigger">
|
||||||
<div class="upload-icon">+</div>
|
<div class="upload-icon">+</div>
|
||||||
@ -166,20 +169,17 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
</div>
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
|
||||||
<NFormItem>
|
|
||||||
<div style="width: 100%; text-align: left; padding-left: 100px">
|
|
||||||
<NText depth="3" style="font-size: 12px; color: #ff9800">
|
|
||||||
ps:最多上传两张
|
|
||||||
</NText>
|
|
||||||
</div>
|
|
||||||
</NFormItem>
|
|
||||||
</NForm>
|
</NForm>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div style="display: flex; justify-content: flex-end; gap: 12px">
|
<div v-if="mode !== 'view'" style="display: flex; justify-content: flex-end; gap: 12px">
|
||||||
<NButton @click="handleClose">取消</NButton>
|
<NButton @click="handleClose">取消</NButton>
|
||||||
<NButton type="primary" @click="handleConfirm">确定</NButton>
|
<NButton type="primary" @click="handleConfirm">确定</NButton>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else style="display: flex; justify-content: flex-end; gap: 12px">
|
||||||
|
<NButton @click="handleClose">关闭</NButton>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
</template>
|
</template>
|
||||||
@ -192,8 +192,6 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
.upload-trigger {
|
.upload-trigger {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
border: 2px dashed #d9d9d9;
|
|
||||||
border-radius: 4px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -201,10 +199,6 @@ const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
|
|||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-trigger:hover {
|
|
||||||
border-color: #40a9ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-icon {
|
.upload-icon {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
color: #d9d9d9;
|
color: #d9d9d9;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
NSwitch,
|
NSwitch,
|
||||||
NTag,
|
NTag,
|
||||||
NPopconfirm,
|
NPopconfirm,
|
||||||
|
NDatePicker,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
|
|
||||||
import CommonPage from '@/components/page/CommonPage.vue'
|
import CommonPage from '@/components/page/CommonPage.vue'
|
||||||
@ -69,21 +70,21 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
width: 80,
|
width: 100,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
ellipsis: { tooltip: true },
|
ellipsis: { tooltip: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '手机号',
|
title: '手机号',
|
||||||
key: 'phone',
|
key: 'phone',
|
||||||
width: 120,
|
width: 140,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
ellipsis: { tooltip: true },
|
ellipsis: { tooltip: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '微信号',
|
title: '微信号',
|
||||||
key: 'wechat',
|
key: 'wechat',
|
||||||
width: 120,
|
width: 140,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
ellipsis: { tooltip: true },
|
ellipsis: { tooltip: true },
|
||||||
render(row) {
|
render(row) {
|
||||||
@ -94,7 +95,7 @@ const columns = [
|
|||||||
title: '注册时间',
|
title: '注册时间',
|
||||||
key: 'created_at',
|
key: 'created_at',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 160,
|
width: 180,
|
||||||
ellipsis: { tooltip: true },
|
ellipsis: { tooltip: true },
|
||||||
render(row) {
|
render(row) {
|
||||||
return row.created_at ? formatDate(row.created_at) : '-'
|
return row.created_at ? formatDate(row.created_at) : '-'
|
||||||
@ -116,7 +117,7 @@ const columns = [
|
|||||||
width: 120,
|
width: 120,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render(row) {
|
render(row) {
|
||||||
return row.remaining_count || 0
|
return row.remaining_count !== undefined ? row.remaining_count : 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -248,24 +249,36 @@ const validateForm = {
|
|||||||
:get-data="api.getAppUserList"
|
:get-data="api.getAppUserList"
|
||||||
>
|
>
|
||||||
<template #queryBar>
|
<template #queryBar>
|
||||||
<QueryBarItem label="手机号" :label-width="50">
|
<QueryBarItem label="手机号" :label-width="60">
|
||||||
<NInput
|
<NInput
|
||||||
v-model:value="queryItems.phone"
|
v-model:value="queryItems.phone"
|
||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入手机号"
|
placeholder="请输入手机号"
|
||||||
|
style="width: 200px"
|
||||||
@keypress.enter="$table?.handleSearch()"
|
@keypress.enter="$table?.handleSearch()"
|
||||||
/>
|
/>
|
||||||
</QueryBarItem>
|
</QueryBarItem>
|
||||||
<QueryBarItem label="微信号" :label-width="50">
|
<QueryBarItem label="微信号" :label-width="60">
|
||||||
<NInput
|
<NInput
|
||||||
v-model:value="queryItems.wechat"
|
v-model:value="queryItems.wechat"
|
||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入微信号"
|
placeholder="请输入微信号"
|
||||||
|
style="width: 200px"
|
||||||
@keypress.enter="$table?.handleSearch()"
|
@keypress.enter="$table?.handleSearch()"
|
||||||
/>
|
/>
|
||||||
</QueryBarItem>
|
</QueryBarItem>
|
||||||
|
<QueryBarItem label="注册时间" :label-width="70">
|
||||||
|
<NDatePicker
|
||||||
|
v-model:value="queryItems.created_at"
|
||||||
|
type="daterange"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择注册时间"
|
||||||
|
style="width: 280px"
|
||||||
|
@update:value="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
</template>
|
</template>
|
||||||
</CrudTable>
|
</CrudTable>
|
||||||
|
|
||||||
|
|||||||
@ -265,35 +265,102 @@ const handleCertificateConfirm = (data) => {
|
|||||||
</NTabPane>
|
</NTabPane>
|
||||||
<NTabPane name="flow" tab="计算流程">
|
<NTabPane name="flow" tab="计算流程">
|
||||||
<NSpin :show="loading">
|
<NSpin :show="loading">
|
||||||
<div class="calc-summary">
|
<div class="calc-flow-container">
|
||||||
<div class="calc-card">
|
<!-- 左侧:详细计算流程 -->
|
||||||
<p>模型估值(A·B法)</p>
|
<div class="calc-flow-left">
|
||||||
<strong>{{ formatAmount(detailData?.model_value_b) }}</strong>
|
<div class="calc-formula-header">
|
||||||
|
最终估值A12000=模型估值B12*0.7+市场估值C33*0.3
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="calc-section">
|
||||||
|
<div class="calc-section-title">一、模型估值B12=(经济价值B143*0.7+文化价值B255*0.3)*风险调整系数B343</div>
|
||||||
|
|
||||||
|
<div class="calc-subsection">
|
||||||
|
<div class="calc-subsection-title">1、经济价值B143=基础价值B1173*(1+流量因子B1212)*政策驱动B1345</div>
|
||||||
|
|
||||||
|
<div class="calc-item">
|
||||||
|
<div class="calc-item-label">(1) 基础价值B1173=财务价值P2000*(0.45+0.05*行业系数I0.8)+法律强度L0.3*(0.35+0.05*行业系数I0.8)+发展潜力D0.5*0.2</div>
|
||||||
|
<div class="calc-detail">
|
||||||
|
<div class="calc-detail-item">• 财务价值P2000=[3年内均收益10000*(1+增长率23%)*5]/5</div>
|
||||||
|
<div class="calc-detail-item">• 法律强度L12=专利分*12*0.4+商标分*12*0.3+版权分*12*0.3</div>
|
||||||
|
<div class="calc-detail-item">• 发展潜力D=专利分*0.5+ESG分*0.2+创新投入比*0.3</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="calc-item">
|
||||||
|
<div class="calc-item-label">(2) 流量因子B1212</div>
|
||||||
|
<div class="calc-detail">
|
||||||
|
<div class="calc-detail-item">• 近 30 天搜索指数M1</div>
|
||||||
|
<div class="calc-detail-item">• 行业均值S2</div>
|
||||||
|
<div class="calc-detail-item">• 社交媒体传播度S3</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="calc-item">
|
||||||
|
<div class="calc-item-label">(3) 政策驱动B13</div>
|
||||||
|
<div class="calc-detail">
|
||||||
|
<div class="calc-detail-item">• 政策契合度P</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="calc-subsection">
|
||||||
|
<div class="calc-subsection-title">2、文化价值B2</div>
|
||||||
|
|
||||||
|
<div class="calc-item">
|
||||||
|
<div class="calc-item-label">(1) 活态传承系数B21</div>
|
||||||
|
<div class="calc-detail">
|
||||||
|
<div class="calc-detail-item">• 传承人等级系数</div>
|
||||||
|
<div class="calc-detail-item">• 教学传播频次</div>
|
||||||
|
<div class="calc-detail-item">• 跨界合作深度</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="calc-item">
|
||||||
|
<div class="calc-item-label">(2) 纹样基因值B22</div>
|
||||||
|
<div class="calc-detail">
|
||||||
|
<div class="calc-detail-item">• 纹样复杂度SC</div>
|
||||||
|
<div class="calc-detail-item">• 归一化稀缺H</div>
|
||||||
|
<div class="calc-detail-item">• 历史承载度HI</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:计算流程大纲 -->
|
||||||
|
<div class="calc-flow-right">
|
||||||
|
<div class="calc-outline-title">最终估值A</div>
|
||||||
|
<div class="calc-outline">
|
||||||
|
<div class="outline-section">
|
||||||
|
<div class="outline-title">一、模型估值B</div>
|
||||||
|
<div class="outline-subsection">
|
||||||
|
<div class="outline-subtitle">1、经济价值B1</div>
|
||||||
|
<div class="outline-item">(1) 基础价值B11</div>
|
||||||
|
<div class="outline-detail">• 基础价值B1173=财务价值P2000*(0.45+0.05*行业系数I0.8)+法律强度L0.3*(0.35+0.05*行业系数I0.8)+发展潜力D0.5*0.2</div>
|
||||||
|
<div class="outline-item">(2) 流量因子B12</div>
|
||||||
|
<div class="outline-detail">• 近 30 天搜索指数M1</div>
|
||||||
|
<div class="outline-detail">• 行业均值S2</div>
|
||||||
|
<div class="outline-detail">• 社交媒体传播度S3</div>
|
||||||
|
<div class="outline-item">(3) 政策驱动B13</div>
|
||||||
|
<div class="outline-detail">• 政策契合度P</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="outline-subsection">
|
||||||
|
<div class="outline-subtitle">2、文化价值B2</div>
|
||||||
|
<div class="outline-item">(1) 活态传承系数B21</div>
|
||||||
|
<div class="outline-detail">• 传承人等级系数</div>
|
||||||
|
<div class="outline-detail">• 教学传播频次</div>
|
||||||
|
<div class="outline-detail">• 跨界合作深度</div>
|
||||||
|
<div class="outline-item">(2) 纹样基因值B22</div>
|
||||||
|
<div class="outline-detail">• 纹样复杂度SC</div>
|
||||||
|
<div class="outline-detail">• 归一化稀缺H</div>
|
||||||
|
<div class="outline-detail">• 历史承载度HI</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="calc-card">
|
|
||||||
<p>市场对标估值</p>
|
|
||||||
<strong>{{ formatAmount(detailData?.market_value_c) }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="calc-card">
|
|
||||||
<p>综合校准估值</p>
|
|
||||||
<strong>{{ formatAmount(detailData?.final_value_ab) }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="calc-card">
|
|
||||||
<p>动态质押率</p>
|
|
||||||
<strong>{{ formatPercent(detailData?.dynamic_pledge_rate) }}</strong>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="calcFlow.length" class="calc-flow">
|
|
||||||
<div v-for="(step, index) in calcFlow" :key="index" class="calc-step">
|
|
||||||
<div class="step-index">{{ index + 1 }}</div>
|
|
||||||
<div class="step-body">
|
|
||||||
<p class="step-title">{{ step.title }}</p>
|
|
||||||
<p class="step-desc">{{ step.description }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="step-value">{{ step.value }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="calc-empty">暂无计算流程数据</div>
|
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</NTabPane>
|
</NTabPane>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
@ -456,75 +523,141 @@ const handleCertificateConfirm = (data) => {
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-summary {
|
/* 计算流程容器 */
|
||||||
display: grid;
|
.calc-flow-container {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
display: flex;
|
||||||
gap: 16px;
|
gap: 24px;
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧详细流程 */
|
||||||
|
.calc-flow-left {
|
||||||
|
flex: 1;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-formula-header {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 2px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-subsection {
|
||||||
|
margin-left: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-card {
|
.calc-subsection-title {
|
||||||
padding: 16px;
|
font-size: 15px;
|
||||||
border: 1px solid #eef0f6;
|
font-weight: 600;
|
||||||
border-radius: 10px;
|
color: #374151;
|
||||||
background: #fdfdff;
|
margin-bottom: 12px;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-card p {
|
.calc-item {
|
||||||
margin: 0 0 8px;
|
margin-left: 20px;
|
||||||
color: #888;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-card strong {
|
.calc-item-label {
|
||||||
font-size: 18px;
|
font-size: 14px;
|
||||||
|
color: #4b5563;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-detail {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-detail-item {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 右侧大纲 */
|
||||||
|
.calc-flow-right {
|
||||||
|
width: 320px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calc-outline-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 2px solid #e5e7eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-flow {
|
.calc-outline {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calc-step {
|
|
||||||
display: flex;
|
|
||||||
gap: 16px;
|
|
||||||
align-items: center;
|
|
||||||
padding: 16px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px dashed #dce1f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-index {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #eef4ff;
|
|
||||||
color: #3b82f6;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-body {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-title {
|
|
||||||
margin: 0 0 6px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-desc {
|
|
||||||
margin: 0;
|
|
||||||
color: #666;
|
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-value {
|
.outline-section {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-title {
|
||||||
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-subsection {
|
||||||
|
margin-left: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-subtitle {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-item {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #4b5563;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-detail {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-left: 24px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calc-empty {
|
.calc-empty {
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import {
|
|||||||
NButton,
|
NButton,
|
||||||
NUpload,
|
NUpload,
|
||||||
NText,
|
NText,
|
||||||
NImage
|
NImage,
|
||||||
|
NImageGroup
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
// 临时移除图标导入以解决模块解析问题
|
// 临时移除图标导入以解决模块解析问题
|
||||||
// import { DownloadIcon } from '@vicons/tabler'
|
// import { DownloadIcon } from '@vicons/tabler'
|
||||||
@ -142,13 +143,32 @@ const handleDownloadReport = () => {
|
|||||||
|
|
||||||
// 文件预览
|
// 文件预览
|
||||||
const handlePreview = (file) => {
|
const handlePreview = (file) => {
|
||||||
// 图片和PDF可以直接预览
|
// 对于非图片文件,显示提示
|
||||||
if (file.type?.startsWith('image/') || file.type === 'application/pdf') {
|
if (!file.type?.startsWith('image/')) {
|
||||||
window.open(file.url || '', '_blank')
|
$message.info('此文件类型不支持预览,请下载查看')
|
||||||
} else {
|
return false
|
||||||
console.log('此文件类型不支持预览')
|
|
||||||
// TODO: 添加用户提示
|
|
||||||
}
|
}
|
||||||
|
// 图片文件返回 true,让 NUpload 使用内置预览
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件下载
|
||||||
|
const handleDownload = (file) => {
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = file.url || ''
|
||||||
|
link.download = file.name || 'download'
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义上传预览
|
||||||
|
const customRequest = ({ file, onFinish, onError }) => {
|
||||||
|
// 这里可以实现自定义上传逻辑
|
||||||
|
// 暂时模拟上传成功
|
||||||
|
setTimeout(() => {
|
||||||
|
onFinish()
|
||||||
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const modalTitle = computed(() => {
|
const modalTitle = computed(() => {
|
||||||
@ -168,18 +188,17 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
style="width: 700px"
|
style="width: 700px"
|
||||||
@update:show="handleClose"
|
@update:show="handleClose"
|
||||||
>
|
>
|
||||||
<!-- 上传模式 -->
|
<!-- 上传/查看模式 -->
|
||||||
<div v-if="isUploadMode" class="certificate-content">
|
<div class="certificate-content">
|
||||||
<!-- 报告上传部分 -->
|
<!-- 报告上传部分 -->
|
||||||
<div class="upload-section">
|
<div class="upload-section">
|
||||||
|
<div class="section-header">
|
||||||
<div class="section-title">报告:</div>
|
<div class="section-title">报告:</div>
|
||||||
<div class="upload-content">
|
|
||||||
<div class="download-section">
|
|
||||||
<NButton text type="primary" @click="handleDownloadReport">
|
<NButton text type="primary" @click="handleDownloadReport">
|
||||||
点击下载原版报告
|
点击下载原版报告
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="upload-content">
|
||||||
<NUpload
|
<NUpload
|
||||||
v-model:file-list="reportFileList"
|
v-model:file-list="reportFileList"
|
||||||
:max="5"
|
:max="5"
|
||||||
@ -187,6 +206,11 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
@change="handleReportUploadChange"
|
@change="handleReportUploadChange"
|
||||||
@remove="handleRemove"
|
@remove="handleRemove"
|
||||||
|
:custom-request="customRequest"
|
||||||
|
:disabled="!isUploadMode"
|
||||||
|
show-preview-button
|
||||||
|
show-download-button
|
||||||
|
@download="handleDownload"
|
||||||
>
|
>
|
||||||
</NUpload>
|
</NUpload>
|
||||||
</div>
|
</div>
|
||||||
@ -203,64 +227,17 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
@change="handleCertificateUploadChange"
|
@change="handleCertificateUploadChange"
|
||||||
@remove="handleRemove"
|
@remove="handleRemove"
|
||||||
|
:custom-request="customRequest"
|
||||||
|
:disabled="!isUploadMode"
|
||||||
|
show-preview-button
|
||||||
|
show-download-button
|
||||||
|
@download="handleDownload"
|
||||||
>
|
>
|
||||||
</NUpload>
|
</NUpload>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 查看模式 -->
|
|
||||||
<div v-else class="certificate-content">
|
|
||||||
<!-- 报告查看部分 -->
|
|
||||||
<div class="view-section">
|
|
||||||
<div class="section-title">报告:</div>
|
|
||||||
<div class="view-content">
|
|
||||||
<div class="download-area">
|
|
||||||
<NButton text type="primary" @click="handleDownloadReport">
|
|
||||||
<!-- 临时移除图标 -->
|
|
||||||
<!-- <template #icon>
|
|
||||||
<NIcon :component="DownloadIcon" />
|
|
||||||
</template> -->
|
|
||||||
点击下载原版报告
|
|
||||||
</NButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="reportFileList.length > 0" class="file-info">
|
|
||||||
<NText>{{ reportFileList[0]?.name }} 下载</NText>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 证书查看部分 -->
|
|
||||||
<div class="view-section">
|
|
||||||
<div class="section-title">证书:</div>
|
|
||||||
<div class="view-content">
|
|
||||||
<div v-if="certificateFileList.length === 0" class="empty-state">
|
|
||||||
<NText depth="3">暂无证书文件</NText>
|
|
||||||
</div>
|
|
||||||
<div v-else class="certificate-display">
|
|
||||||
<div
|
|
||||||
v-for="file in certificateFileList"
|
|
||||||
:key="file.id"
|
|
||||||
class="certificate-image"
|
|
||||||
@click="handlePreview(file)"
|
|
||||||
>
|
|
||||||
<NImage
|
|
||||||
v-if="file.type?.startsWith('image/')"
|
|
||||||
:src="file.url"
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
objectFit="cover"
|
|
||||||
preview-disabled
|
|
||||||
/>
|
|
||||||
<div v-else class="file-icon">
|
|
||||||
{{ file.name?.split('.').pop()?.toUpperCase() || 'FILE' }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@ -293,11 +270,18 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 12px;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-content {
|
.upload-content {
|
||||||
@ -405,44 +389,6 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-display {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.certificate-image {
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.certificate-image:hover {
|
|
||||||
border-color: #1890ff;
|
|
||||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
|
||||||
padding: 40px 20px;
|
|
||||||
text-align: center;
|
|
||||||
color: #999;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-icon {
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #f5f5f5;
|
|
||||||
color: #666;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 600;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 底部按钮 */
|
/* 底部按钮 */
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
@ -474,12 +420,5 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
|||||||
width: 95vw !important;
|
width: 95vw !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-display {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.certificate-image {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user