提取docx、xlsx、xls文件内容并填充,修改页面样式
This commit is contained in:
parent
df332f8138
commit
3e39671644
|
|
@ -38,11 +38,11 @@
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"fuse.js": "6.4.3",
|
"fuse.js": "6.4.3",
|
||||||
"highlight.js": "9.18.5",
|
"highlight.js": "9.18.5",
|
||||||
|
"jquery": "^3.6.0",
|
||||||
|
"jquery-mousewheel": "^3.1.13",
|
||||||
"js-beautify": "1.13.0",
|
"js-beautify": "1.13.0",
|
||||||
"js-cookie": "3.0.1",
|
"js-cookie": "3.0.1",
|
||||||
"jsencrypt": "3.0.0-rc.1",
|
"jsencrypt": "3.0.0-rc.1",
|
||||||
"jquery": "^3.6.0",
|
|
||||||
"jquery-mousewheel": "^3.1.13",
|
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luckysheet": "^2.1.13",
|
"luckysheet": "^2.1.13",
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ import {
|
||||||
uploadSmallFile,
|
uploadSmallFile,
|
||||||
uploadLargeFile,
|
uploadLargeFile,
|
||||||
} from '@/api/common/uploadFile.js'
|
} from '@/api/common/uploadFile.js'
|
||||||
|
import mammoth from 'mammoth'
|
||||||
|
import * as XLSX from 'xlsx'
|
||||||
|
|
||||||
// 常量定义
|
// 常量定义
|
||||||
const FILE_STATUS = {
|
const FILE_STATUS = {
|
||||||
|
|
@ -304,6 +306,22 @@ export default {
|
||||||
|
|
||||||
// 上传成功处理
|
// 上传成功处理
|
||||||
handleSuccess(response, file) {
|
handleSuccess(response, file) {
|
||||||
|
const fileExt = this.getFileExtension(file.name);
|
||||||
|
if (fileExt === 'docx') {
|
||||||
|
this.parseDocxFile(file.raw).then(text => {
|
||||||
|
// 将解析出的文本传递给父组件处理OCR逻辑
|
||||||
|
this.$emit('docx-content', text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (fileExt === 'xlsx' || fileExt === 'xls') {
|
||||||
|
this.parseXlsxFile(file.raw).then(text => {
|
||||||
|
this.$emit('xlsx-content', text); // 触发xlsx内容事件
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('xlsx解析失败:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.$bus.$emit('endUpload')
|
this.$bus.$emit('endUpload')
|
||||||
this.updateFileStatus(file.uid, FILE_STATUS.SUCCESS, '', response.data, 100)
|
this.updateFileStatus(file.uid, FILE_STATUS.SUCCESS, '', response.data, 100)
|
||||||
this.$emit('file-change', this.getCurrentFiles(), this.type)
|
this.$emit('file-change', this.getCurrentFiles(), this.type)
|
||||||
|
|
@ -318,6 +336,53 @@ export default {
|
||||||
this.isUploading = false
|
this.isUploading = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
parseDocxFile(file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
const arrayBuffer = e.target.result;
|
||||||
|
// 使用mammoth解析docx
|
||||||
|
mammoth.extractRawText({ arrayBuffer })
|
||||||
|
.then(result => {
|
||||||
|
resolve(result.value); // 提取的纯文本内容
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('docx解析失败:', err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
parseXlsxFile(file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
try {
|
||||||
|
// 读取二进制数据
|
||||||
|
const data = new Uint8Array(e.target.result);
|
||||||
|
// 解析Excel文件
|
||||||
|
const workbook = XLSX.read(data, { type: 'array' });
|
||||||
|
// 获取第一个工作表
|
||||||
|
const firstSheetName = workbook.SheetNames[0];
|
||||||
|
const worksheet = workbook.Sheets[firstSheetName];
|
||||||
|
// 转换为JSON(只解析前100行,避免大文件性能问题)
|
||||||
|
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, range: 0, raw: false });
|
||||||
|
// 转换为文本格式(按行拼接,用换行分隔)
|
||||||
|
const text = jsonData.map(row => row.join('\t')).join('\n');
|
||||||
|
resolve(text);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('xlsx解析失败:', err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 读取文件为二进制
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 工具方法
|
// 工具方法
|
||||||
getFileExtension(filename) {
|
getFileExtension(filename) {
|
||||||
return filename.split('.').pop().toLowerCase()
|
return filename.split('.').pop().toLowerCase()
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,8 @@ export default {
|
||||||
this.$refs.financialStatement.validate()
|
this.$refs.financialStatement.validate()
|
||||||
])
|
])
|
||||||
|
|
||||||
|
console.log('处理后的年份:', financeReportData);
|
||||||
|
|
||||||
// 2. 初始化提交数据,合并两个子组件的非文件字段
|
// 2. 初始化提交数据,合并两个子组件的非文件字段
|
||||||
const formData = {
|
const formData = {
|
||||||
...financeReportData, // 财务报告的非文件字段(fileName、reportYear 等)
|
...financeReportData, // 财务报告的非文件字段(fileName、reportYear 等)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
@del-file="handleDelFile"
|
@del-file="handleDelFile"
|
||||||
:uploadType="uploadType"
|
:uploadType="uploadType"
|
||||||
:maxFileTips="maxFileTips"
|
:maxFileTips="maxFileTips"
|
||||||
|
@docx-content="handleDocxContent"
|
||||||
:limitUploadNum="1"
|
:limitUploadNum="1"
|
||||||
type="finance_report"
|
type="finance_report"
|
||||||
:show-file-list="true"
|
:show-file-list="true"
|
||||||
|
|
@ -69,7 +70,7 @@ export default {
|
||||||
dicts: ['identification_tag'],
|
dicts: ['identification_tag'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
uploadType: 'pdf、doc、docx',
|
uploadType: 'docx',
|
||||||
maxFileTips: '100MB',
|
maxFileTips: '100MB',
|
||||||
ocrRuleList: ['finance_report'],
|
ocrRuleList: ['finance_report'],
|
||||||
fileUploadList: [],
|
fileUploadList: [],
|
||||||
|
|
@ -112,6 +113,57 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
handleDocxContent(text) {
|
||||||
|
// 模拟OCR返回格式,将docx文本包装成现有逻辑可处理的结构
|
||||||
|
|
||||||
|
const mockOcrResult = {
|
||||||
|
status_code: 200,
|
||||||
|
data: {
|
||||||
|
chat_res: this.extractInfoFromDocx(text) // 从文本中提取关键信息
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 复用OCR结果处理逻辑(填充报告年份)
|
||||||
|
this.handleOcrResultWithMock(mockOcrResult);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 从docx文本中提取信息(核心:根据业务规则匹配关键词)
|
||||||
|
extractInfoFromDocx(text) {
|
||||||
|
console.log("text", text);
|
||||||
|
// 优化正则:匹配“年份:2026”“年份:2026”“2026年”“2026年度”等格式
|
||||||
|
const yearMatch = text.match(
|
||||||
|
/(年份|报告年份|年度)\s*[::]\s*(\d{4})|(\d{4})\s*(年|年度)/
|
||||||
|
);
|
||||||
|
console.log("yearMatch", yearMatch);
|
||||||
|
// 提取匹配到的年份(优先取冒号后的年份,再取数字+年/年度的格式)
|
||||||
|
const year = yearMatch ? (yearMatch[2] || yearMatch[3]) : '';
|
||||||
|
return { "报告年份": year };
|
||||||
|
},
|
||||||
|
|
||||||
|
// 复用原OCR结果处理逻辑
|
||||||
|
handleOcrResultWithMock(ocrResult) {
|
||||||
|
|
||||||
|
if (ocrResult.status_code === 200) {
|
||||||
|
const chat_res = ocrResult.data?.chat_res;
|
||||||
|
if (chat_res && typeof chat_res === 'object') {
|
||||||
|
Object.keys(chat_res).forEach(key => {
|
||||||
|
const formField = this.ocrResultParams[key];
|
||||||
|
if (formField === 'reportYear' && chat_res[key]) {
|
||||||
|
const year = chat_res[key].replace(/[^\d]/g, '');
|
||||||
|
this.formData[formField] = year.length === 4 ? year : '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$message.success('docx内容解析成功,已自动填充报告年份');
|
||||||
|
this.$refs.financeReportForm.validateField('reportYear');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$message.error(`年份提取失败: ${ocrResult.status_msg || '未找到有效年份'}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setFormData(data) {
|
setFormData(data) {
|
||||||
// 财务报告文件:不手动生成uid
|
// 财务报告文件:不手动生成uid
|
||||||
const financeFiles = Array.isArray(data.fileList)
|
const financeFiles = Array.isArray(data.fileList)
|
||||||
|
|
@ -125,11 +177,22 @@ export default {
|
||||||
}))
|
}))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
let reportYear = data.reportYear || '';
|
||||||
|
if (reportYear) {
|
||||||
|
if (typeof reportYear === 'string') {
|
||||||
|
reportYear = reportYear.split('-')[0];
|
||||||
|
}
|
||||||
|
if (typeof reportYear === 'number') {
|
||||||
|
reportYear = reportYear.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.formData = {
|
this.formData = {
|
||||||
...(data || {}),
|
...(data || {}),
|
||||||
fileList: financeFiles,
|
fileList: financeFiles,
|
||||||
fileName: financeFiles.length > 0 ? this.getFileName(financeFiles[0]) : '',
|
fileName: financeFiles.length > 0 ? this.getFileName(financeFiles[0]) : '',
|
||||||
delFileList: []
|
delFileList: [],
|
||||||
|
reportYear: reportYear,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -148,12 +211,10 @@ export default {
|
||||||
|
|
||||||
handleFileChange(files, type) {
|
handleFileChange(files, type) {
|
||||||
if (type === 'finance_report' && files instanceof Array) {
|
if (type === 'finance_report' && files instanceof Array) {
|
||||||
// 处理文件替换逻辑
|
if (files.length > 0 && files[0].response) {
|
||||||
if (files.length > 0 && files[0].response) { // 验证上传成功
|
|
||||||
// 标记为已完成替换
|
|
||||||
this.isReplacingFile = false;
|
this.isReplacingFile = false;
|
||||||
|
|
||||||
// 处理旧文件删除
|
// 处理旧文件删除(保持不变)
|
||||||
if (this.formData.fileList.length > 0) {
|
if (this.formData.fileList.length > 0) {
|
||||||
const oldFile = this.formData.fileList[0];
|
const oldFile = this.formData.fileList[0];
|
||||||
const delPath = oldFile?.response?.fileRes?.filePath || oldFile?.filePath || null;
|
const delPath = oldFile?.response?.fileRes?.filePath || oldFile?.filePath || null;
|
||||||
|
|
@ -169,16 +230,28 @@ export default {
|
||||||
|
|
||||||
this.formData.fileList = markedFiles;
|
this.formData.fileList = markedFiles;
|
||||||
|
|
||||||
// 提取文件名逻辑不变
|
// 提取文件名(保持不变)
|
||||||
if (markedFiles.length > 0) {
|
if (markedFiles.length > 0) {
|
||||||
const originalFileName = this.getFileName(markedFiles[0])
|
const originalFileName = this.getFileName(markedFiles[0])
|
||||||
const safeFileName = originalFileName.replace(/--+/g, '-')
|
const safeFileName = originalFileName.replace(/--+/g, '-')
|
||||||
this.formData.fileName = safeFileName
|
this.formData.fileName = safeFileName
|
||||||
this.$refs.financeReportForm.validateField('fileName')
|
this.$refs.financeReportForm.validateField('fileName')
|
||||||
}
|
}
|
||||||
this.handleOcrResult(markedFiles)
|
|
||||||
|
//根据文件类型选择解析方式
|
||||||
|
const firstFile = markedFiles[0];
|
||||||
|
const fileExt = this.getFileExt(firstFile).toLowerCase(); // 获取文件后缀
|
||||||
|
if (['doc', 'docx'].includes(fileExt)) {
|
||||||
|
// doc/docx文件:只执行你的自定义解析(不调用OCR)
|
||||||
|
} else if (['pdf', 'jpg', 'jpeg', 'png'].includes(fileExt)) {
|
||||||
|
// pdf/图片:执行原OCR逻辑
|
||||||
|
this.handleOcrResult(markedFiles);
|
||||||
|
} else {
|
||||||
|
// 其他格式:提示不支持
|
||||||
|
this.$message.warning('不支持的文件格式,无法解析年份');
|
||||||
|
}
|
||||||
|
|
||||||
} else if (!this.isReplacingFile) {
|
} else if (!this.isReplacingFile) {
|
||||||
// 只有非替换操作才清空文件列表
|
|
||||||
this.formData.fileList = [];
|
this.formData.fileList = [];
|
||||||
this.formData.fileName = '';
|
this.formData.fileName = '';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
:maxFileTips="maxFileTips"
|
:maxFileTips="maxFileTips"
|
||||||
:limitUploadNum="1"
|
:limitUploadNum="1"
|
||||||
type="financial_statement"
|
type="financial_statement"
|
||||||
|
@xlsx-content="handleXlsxContent"
|
||||||
:show-file-list="true"
|
:show-file-list="true"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -144,7 +145,7 @@ export default {
|
||||||
dicts: ['identification_tag'],
|
dicts: ['identification_tag'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
uploadType: 'pdf、doc、docx',
|
uploadType: 'xlsx、xls',
|
||||||
maxFileTips: '100MB',
|
maxFileTips: '100MB',
|
||||||
ocrRuleList: ['financial_statement'],
|
ocrRuleList: ['financial_statement'],
|
||||||
fileUploadList: [],
|
fileUploadList: [],
|
||||||
|
|
@ -231,6 +232,56 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
handleXlsxContent(text) {
|
||||||
|
this.$bus.$emit('startUpload', '正在解析Excel财务数据')
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从Excel文本中提取财务数据
|
||||||
|
const financialData = this.extractFinancialDataFromText(text);
|
||||||
|
// 填充到表单
|
||||||
|
this.fillFormWithFinancialData(financialData);
|
||||||
|
this.$message.success('Excel解析成功,已自动填充财务数据');
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error(`Excel解析失败: ${error.message}`);
|
||||||
|
} finally {
|
||||||
|
this.$bus.$emit('endUpload');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 从文本中提取财务数据(核心逻辑)
|
||||||
|
extractFinancialDataFromText(text) {
|
||||||
|
const data = {};
|
||||||
|
const keywords = Object.keys(this.ocrResultParams); // 获取所有财务指标关键词
|
||||||
|
|
||||||
|
// 遍历每个关键词,在文本中匹配对应值
|
||||||
|
keywords.forEach(keyword => {
|
||||||
|
// 正则:匹配"关键词: 值"或"关键词 值"(支持中英文标点、空格)
|
||||||
|
const regex = new RegExp(`${keyword}\\s*[::]?\\s*([\\d,.%]+)`, 'i');
|
||||||
|
const match = text.match(regex);
|
||||||
|
|
||||||
|
if (match && match[1]) {
|
||||||
|
// 提取数值(去除千分位逗号等干扰符)
|
||||||
|
data[keyword] = match[1].replace(/,/g, '').trim();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 将提取的财务数据填充到表单
|
||||||
|
fillFormWithFinancialData(financialData) {
|
||||||
|
Object.keys(financialData).forEach(keyword => {
|
||||||
|
const formField = this.ocrResultParams[keyword];
|
||||||
|
if (formField) {
|
||||||
|
// 保留数字、小数点和百分号(清除其他字符)
|
||||||
|
this.formData[formField] = financialData[keyword].replace(/[^\d.%]/g, '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 触发表单验证
|
||||||
|
this.$refs.financialStatementForm.validate();
|
||||||
|
},
|
||||||
|
|
||||||
setFormData(data) {
|
setFormData(data) {
|
||||||
// 财务报表文件:不手动生成uid
|
// 财务报表文件:不手动生成uid
|
||||||
const financialFiles = Array.isArray(data.fileList)
|
const financialFiles = Array.isArray(data.fileList)
|
||||||
|
|
@ -284,9 +335,14 @@ export default {
|
||||||
})).slice(-1);
|
})).slice(-1);
|
||||||
|
|
||||||
this.formData.fileList = markedFiles;
|
this.formData.fileList = markedFiles;
|
||||||
this.handleOcrResult(markedFiles)
|
const fileExt = this.getFileExt(markedFiles[0]);
|
||||||
|
if (['xls', 'xlsx'].includes(fileExt)) {
|
||||||
|
// 已通过@xlsx-content处理,此处无需额外操作
|
||||||
|
} else {
|
||||||
|
// 非Excel文件走原有OCR逻辑
|
||||||
|
this.handleOcrResult(markedFiles);
|
||||||
|
}
|
||||||
} else if (!this.isReplacingFile) {
|
} else if (!this.isReplacingFile) {
|
||||||
// 只有非替换操作才清空文件列表
|
|
||||||
this.formData.fileList = [];
|
this.formData.fileList = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ export default {
|
||||||
dicts: ['identification_tag'],
|
dicts: ['identification_tag'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
uploadType: 'doc、docx',
|
uploadType: 'jpg、png、pdf',
|
||||||
maxFileTips: '100MB',
|
maxFileTips: '100MB',
|
||||||
ocrRuleList: ['qualification_certificate'], // 资质证书OCR识别规则
|
ocrRuleList: ['qualification_certificate'], // 资质证书OCR识别规则
|
||||||
fileUploadList: [],
|
fileUploadList: [],
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
<!-- 资质卡片网格 -->
|
<!-- 资质卡片网格 -->
|
||||||
<div class="qualification-grid">
|
<div class="qualification-grid">
|
||||||
<!-- 新增资质卡片 -->
|
<!-- 新增资质卡片 -->
|
||||||
<div class="grid-item">
|
<div class="qualification-card-wrapper">
|
||||||
<div
|
<div
|
||||||
class="qualification-card create-card"
|
class="qualification-card create-card"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 资质信息卡片及下方的过期提示 -->
|
<!-- 资质信息卡片及下方的过期提示 -->
|
||||||
<div class="grid-item" v-for="item in qualificationList" :key="item.qualificationId">
|
<div class="qualification-card-wrapper" v-for="item in qualificationList" :key="item.qualificationId">
|
||||||
<!-- 卡片本身 -->
|
<!-- 卡片本身 -->
|
||||||
<div class="qualification-card">
|
<div class="qualification-card">
|
||||||
<div class="qualification-header">
|
<div class="qualification-header">
|
||||||
|
|
@ -114,8 +114,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 过期提示 -->
|
<!-- 过期提示 -->
|
||||||
<div class="expired-tag" v-if="item.isExpired">
|
<div class="expired-tags" v-if="item.isExpired">
|
||||||
<i class="el-icon-warning"></i> {{ item.certificateName || '证书' }}已过期
|
<span class="expired-text">证书已过期</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -220,7 +220,6 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
loadQualificationTypeDict() {
|
loadQualificationTypeDict() {
|
||||||
|
|
||||||
// getDicts 的参数是字典类型编码:qualification_type
|
// getDicts 的参数是字典类型编码:qualification_type
|
||||||
this.getDicts('qualification_type').then(response => {
|
this.getDicts('qualification_type').then(response => {
|
||||||
this.qualificationTypeOptions = response.data.map(item => ({
|
this.qualificationTypeOptions = response.data.map(item => ({
|
||||||
|
|
@ -459,36 +458,35 @@ export default {
|
||||||
.qualification-grid {
|
.qualification-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
gap: 20px;
|
gap: 24px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
max-height: calc(100vh - 280px);
|
max-height: calc(100vh - 280px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 10px;
|
padding: 20px 6px 20px 0px;
|
||||||
|
align-items: start;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
&::-webkit-scrollbar-track {
|
||||||
background: #f1f1f1;
|
background: transparent;
|
||||||
border-radius: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background: #c1c1c1;
|
background: rgba(0, 0, 0, 0.2);
|
||||||
border-radius: 4px;
|
border-radius: 3px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #a8a8a8;
|
background: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网格项容器(包含卡片和下方提示)
|
// 卡片容器(包含卡片和下方提示)
|
||||||
.grid-item {
|
.qualification-card-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px; // 卡片与下方提示的间距
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.qualification-card {
|
.qualification-card {
|
||||||
|
|
@ -645,20 +643,23 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过期提示:放在qualification-card标签的外部下方
|
// 过期提示样式
|
||||||
.expired-tag {
|
.expired-tags {
|
||||||
padding: 6px 0;
|
padding: 8px 12px;
|
||||||
text-align: center;
|
flex-shrink: 0;
|
||||||
background: transparent; // 与页面背景一致
|
|
||||||
color: #ff4d4f; // 字体红色
|
.expired-text {
|
||||||
font-size: 12px;
|
display: block;
|
||||||
font-weight: 500;
|
color: #db3e29;
|
||||||
width: 100%; // 与卡片同宽
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue