2025-06-11 14:38:40 +08:00

505 lines
13 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="brand-system">
<!-- 搜索与筛选 -->
<!-- <div class="system-header">-->
<!-- <el-input v-model="searchQuery" placeholder="搜索制度名称/编号" prefix-icon="el-icon-search" />-->
<!-- <el-select v-model="filterType" placeholder="分类筛选">-->
<!-- <el-option v-for="type in filterTypes" :key="type.value" :label="type.label" :value="type.value" />-->
<!-- </el-select>-->
<!-- </div>-->
<h2>品牌制度</h2>
<!-- 制度列表 -->
<div class="system-list">
<div v-for="(item, index) in filteredList" :key="index" class="system-card" @click="showDetail(item)">
<div class="card-header">
<div class="card-title">
<i class="el-icon-document"></i>
{{ item.title }}
</div>
<div class="card-meta">
<span>编号{{ item.code }}</span>
</div>
</div>
<div class="card-content">
<p>{{ item.desc }}</p>
</div>
<!-- <div class="card-footer">-->
<!-- <span :class="`status-tag ${item.status === '生效中' ? 'active' : 'inactive'}`">{{ item.status }}</span>-->
<!-- <span>生效日期{{ item.effectiveDate }}</span>-->
<!-- </div>-->
</div>
</div>
<!-- 浮层弹窗 -->
<transition name="fade">
<div v-if="showDialog" class="dialog-mask" @click.self="hideDetail">
<div class="dialog-container" :style="{ width: dialogWidth }">
<div class="dialog-header">
<div class="header-left">
<h3>{{ currentDetail.title }}</h3>
<div class="dialog-meta">
<span>编号{{ currentDetail.code }}</span>
<span :class="`status-tag ${currentDetail.status === '生效中' ? 'active' : 'inactive'}`">{{ currentDetail.status }}</span>
</div>
</div>
<div class="dialog-actions">
<el-button icon="el-icon-download" @click.stop="downloadDoc(currentDetail)">下载</el-button>
<el-button icon="el-icon-printer" @click.stop="printDoc">打印</el-button>
<i class="el-icon-close" @click="hideDetail"></i>
</div>
</div>
<div class="dialog-content">
<!-- 使用Markdown-it渲染的HTML内容 -->
<div class="doc-preview" v-html="compiledMarkdown"></div>
</div>
<div class="dialog-footer">
<div class="footer-info">
<p>发布日期{{ currentDetail.publishDate }}</p>
</div>
<el-button @click="hideDetail">关闭</el-button>
</div>
</div>
</div>
</transition>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { ElMessage, ElButton } from 'element-plus';
// 筛选类型
const filterTypes = [
{ label: '全部', value: '' },
{ label: '管理规范', value: 'management' },
{ label: '推广制度', value: 'promotion' },
{ label: '评估体系', value: 'evaluation' },
];
// 状态管理
const searchQuery = ref('');
const filterType = ref('');
const showDialog = ref(false);
const currentDetail = ref({});
const dialogWidth = ref('800px');
// 增强型数据集
const systemList = ref([
{
title: '品牌管理规范V2.0',
code: 'BRM-2023-001',
desc: '包含品牌标识、使用规范、VI应用等内容的最新版本',
content:
'# 品牌管理规范 V2.0\n\n## 第一章 总则\n第一条 本规范适用于集团所有子品牌管理...\n\n## 第二章 标识使用\n第五条 品牌标识不得在以下场景使用:\n1. 非官方宣传材料\n2. 竞品对比文档\n3. 未经审批的第三方平台\n\n## 第三章 数字资产\n第九条 数字资源库包含:\n- 官方LOGO矢量文件\n- 品牌色卡CMYK/RGB/HEX\n- 字体库授权文件\n\n## 第四章 附则\n第十二条 本规范自2023年9月1日起生效原有版本自动废止。',
type: 'management',
file: 'BRM-2023-001.docx',
version: '2.0',
effectiveDate: '2023-09-01',
status: '生效中',
department: '品牌管理中心',
publishDate: '2023-08-25',
},
{
title: '品牌推广制度V1.3',
code: 'BRP-2023-005',
desc: '包含线上线下推广策略、预算分配及效果评估标准',
content:
'# 品牌推广制度 V1.3\n\n## 第一章 推广策略\n\n### 第五条 渠道配置\n- 数字媒体占比40%\n- 户外广告占比25%\n- 活动营销占比20%\n- 公关传播占比15%\n\n## 第二章 预算管理\n\n### 第十条 预算审批流程\n市场部提交方案 → 财务部审核 → 副总裁审批 → 执行备案\n\n## 第三章 效果评估\n\n### 第十六条 KPI指标\n| 指标 | 目标值 | 评估周期 |\n|-------|-------|---------|\n| 品牌认知度 | ≥75% | 季度 |\n| 媒体曝光量 | ≥500万次 | 月度 |\n| 转化率 | ≥3.5% | 月度 |',
type: 'promotion',
file: 'BRP-2023-005.docx',
version: '1.3',
effectiveDate: '2023-07-15',
status: '生效中',
department: '市场推广部',
publishDate: '2023-07-10',
},
{
title: '品牌评估体系V1.0',
code: 'BRA-2023-003',
desc: '基于市场反馈和财务数据的品牌价值评估方法与指标',
content:
'# 品牌评估体系 V1.0\n\n## 一、评估维度\n\n### 1.1 市场维度\n- 市场份额增长率\n- 客户满意度评分\n- 行业影响力指数\n\n### 1.2 财务维度\n- 品牌溢价率\n- ROI计算公式\n- 资产回报率\n\n## 二、评估周期\n\n| 级别 | 评估频率 |\n|------|---------|\n| 核心品牌 | 月度 |\n| 重点品牌 | 双月度 |\n| 新兴品牌 | 季度 |\n## 三、数据采集\n- CRM系统数据\n- 财务报表\n- 第三方调研报告',
type: 'evaluation',
file: 'BRA-2023-003.docx',
version: '1.0',
effectiveDate: '2023-06-01',
status: '生效中',
department: '战略发展部',
publishDate: '2023-05-28',
},
]);
// 过滤列表
const filteredList = computed(() => {
return systemList.value.filter((item) => {
const matchSearch =
item.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
item.desc.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
item.code.toLowerCase().includes(searchQuery.value.toLowerCase());
const matchFilter = filterType.value ? item.type === filterType.value : true;
return matchSearch && matchFilter;
});
});
// 显示详情
const showDetail = (item) => {
currentDetail.value = item;
showDialog.value = true;
};
// 隐藏详情
const hideDetail = () => {
showDialog.value = false;
};
// 下载文档
const downloadDoc = (item) => {
ElMessage.success({
message: `开始下载 ${item.file} (${item.code})`,
duration: 1500,
});
// 实际开发中可替换为真实的下载逻辑
// window.open(`/api/download/${item.id}`);
};
// 打印功能
const printDoc = () => {
ElMessage.info('准备打印文档...');
// 实际开发中可集成打印功能
// window.print();
};
// 在setup函数中
// 恢复 marked 导入
import { marked } from 'marked';
// 恢复 computed 属性
const compiledMarkdown = computed(() => {
return marked.parse(currentDetail.value.content);
});
// 在 setup 函数中配置 editor
const editorConfig = {
readOnly: true,
placeholder: '暂无内容',
showToolbar: false,
// 启用 Markdown 解析
parseMarkdown: true,
};
</script>
<style lang="scss" scoped>
$color-primary: #25bf82;
$color-bg: #f5f7fa;
$color-border: #e4e4e4;
$color-text: #333;
$color-meta: #666;
$color-success: #67c23a;
$color-danger: #ff4949;
.brand-system {
padding: 20px;
background: #fff;
border-radius: 16px;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.system-header {
display: flex;
gap: 20px;
margin-bottom: 24px;
.el-input {
width: 240px;
.el-input__inner {
border-radius: 8px;
border-color: $color-border;
&:focus {
border-color: $color-primary;
box-shadow: 0 0 0 2px rgba(37, 191, 130, 0.2);
}
}
}
.el-select {
width: 160px;
.el-input__inner {
border-radius: 8px;
border-color: $color-border;
}
}
}
.system-list {
margin-top: 20px;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
overflow-y: auto;
}
.system-card {
background: #fff;
border-radius: 12px;
border: 1px solid $color-border;
cursor: pointer;
width: 48%;
transition: all 0.3s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
overflow: hidden;
margin-bottom: 20px;
&:hover {
transform: translateY(-5px);
box-shadow: 0 12px 24px -4px rgba(0, 0, 0, 0.1);
.card-header {
background-color: lighten($color-primary, 40%);
}
}
}
.card-header {
padding: 16px;
background-color: $color-bg;
transition: background-color 0.3s;
}
.card-title {
font-size: 16px;
font-weight: bold;
color: $color-text;
display: flex;
align-items: center;
margin-bottom: 8px;
.el-icon-document {
margin-right: 8px;
color: $color-primary;
font-size: 18px;
}
}
.card-meta {
display: flex;
gap: 12px;
font-size: 12px;
color: $color-meta;
}
.card-content {
padding: 16px;
font-size: 14px;
color: $color-text;
line-height: 1.5;
min-height: 80px;
}
.card-footer {
padding: 12px 16px;
border-top: 1px solid $color-border;
display: flex;
justify-content: space-between;
align-items: center;
background-color: $color-bg;
font-size: 12px;
color: $color-meta;
}
.status-tag {
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
&.active {
background-color: rgba(103, 194, 58, 0.1);
color: $color-success;
}
&.inactive {
background-color: rgba(255, 73, 73, 0.1);
color: $color-danger;
}
}
// 弹窗样式
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.dialog-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.dialog-container {
background: white;
min-width: 500px;
max-width: 90vw;
border-radius: 12px;
overflow: auto;
display: flex;
flex-direction: column;
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.1);
}
.dialog-header {
padding: 20px;
border-bottom: 1px solid $color-border;
display: flex;
justify-content: space-between;
align-items: flex-start;
background-color: #f9fbfc;
.header-left {
h3 {
margin: 0;
font-size: 20px;
font-weight: bold;
color: $color-text;
margin-bottom: 8px;
}
}
}
.dialog-meta {
display: flex;
gap: 16px;
font-size: 14px;
color: $color-meta;
margin-top: 4px;
.status-tag {
padding: 3px 8px;
font-size: 12px;
}
}
.dialog-actions {
display: flex;
gap: 12px;
.el-button {
padding: 10px;
border-radius: 8px;
&:hover {
background-color: lighten($color-primary, 35%);
}
}
.el-icon-close {
font-size: 20px;
cursor: pointer;
margin-left: 12px;
&:hover {
color: $color-primary;
}
}
}
.dialog-content {
padding: 20px;
flex: 1;
overflow-y: hidden;
background-color: #f9fbfc;
}
.doc-preview {
white-space: pre-wrap;
line-height: 1.5;
background: #ffffff;
padding: 20px;
border-radius: 8px;
border: 1px solid $color-border;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
font-family: 'Microsoft Yahei', SimSun, sans-serif;
font-size: 15px;
color: #333;
height: calc(100vh - 300px);
overflow: auto;
/* 恢复 Markdown 元素样式 */
h1,
h2,
h3 {
border-bottom: 1px solid #eee;
padding-bottom: 0.3em;
margin-top: 2em;
}
ul,
ol {
padding-left: 1.5em;
margin: 0.5em 0;
}
li {
margin: 0.3em 0;
}
pre {
background-color: #f8f8f8;
padding: 1em;
border-radius: 4px;
overflow-x: auto;
}
code {
background-color: #eee;
padding: 0.2em 0.4em;
border-radius: 3px;
}
table {
border-collapse: collapse;
width: 100%;
margin: 1em 0;
th,
td {
border: 1px solid #ddd;
padding: 0.5em;
text-align: left;
}
th {
background-color: #f5f7fa;
}
}
}
/* 新增 WangEditor 样式覆盖 */
.w-e-text-container {
background-color: #ffffff !important;
border-radius: 8px 8px 0 0;
padding: 20px;
max-height: 400px;
overflow-y: auto;
}
.w-e-scroll {
height: 400px;
}
.dialog-footer {
padding: 20px;
border-top: 1px solid $color-border;
background-color: #f9fbfc;
.footer-info {
margin-bottom: 16px;
p {
margin: 4px 0;
font-size: 14px;
color: $color-meta;
}
}
}
</style>