923 lines
27 KiB
Vue
923 lines
27 KiB
Vue
<template>
|
||
<div class="apaas-custom-page-mydemo custom-page">
|
||
<template v-if="!showEngineDetail">
|
||
<div class="page-header">
|
||
<div class="title">
|
||
竞品发动机数据
|
||
</div>
|
||
<div class="operation">
|
||
<el-button v-if="hasEngineDataEditPermission()" type="primary" @click="handleDownloadTemplate">下载模板</el-button>
|
||
<el-button v-if="hasEngineDataEditPermission()" class="import-button" @click="handleImport">
|
||
导入机型
|
||
</el-button>
|
||
<el-button v-if="hasEngineDataEditPermission()" type="primary" class="add-button" @click="handleAdd">
|
||
添加机型
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="page-search-panel">
|
||
<div class="searched-fields">
|
||
<div class="searched-field">
|
||
<span class="fielded-label">产品型号</span>
|
||
<el-input v-model="searchPanelValue.modelName" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">状态代号</span>
|
||
<el-input v-model="searchPanelValue.productNumber" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">板块</span>
|
||
<el-input v-model="searchPanelValue.plate" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">平台</span>
|
||
<el-input v-model="searchPanelValue.platform" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">系列</span>
|
||
<el-input v-model="searchPanelValue.series" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">细分市场</span>
|
||
<el-input v-model="searchPanelValue.marketSegment" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">项目名称</span>
|
||
<el-input v-model="searchPanelValue.projectName" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">项目编号</span>
|
||
<el-input v-model="searchPanelValue.projectNumber" placeholder="请输入" />
|
||
</div>
|
||
<div class="searched-field">
|
||
<span class="fielded-label">任务分发状态</span>
|
||
<el-select v-model="searchPanelValue.distributeStatus" placeholder="请选择" clearable>
|
||
<el-option label="已分发" value="已分发" />
|
||
<el-option label="部分分发" value="部分分发" />
|
||
<el-option label="未分发" value="未分发" />
|
||
</el-select>
|
||
</div>
|
||
<div class="search-actions">
|
||
<el-button type="primary" @click="handleSearch">
|
||
查询
|
||
</el-button>
|
||
<el-button @click="resetSearch">
|
||
重置
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="page-data-list">
|
||
<x-vxe-table
|
||
ref="vxeTable"
|
||
:border="true"
|
||
:seqWidth="40"
|
||
:colConfigs="tableConfig.colConfigs"
|
||
:tableData="tableData"
|
||
:rowDraggable="tableConfig.rowDraggable"
|
||
:seqType="tableConfig.seqType"
|
||
:pagination="pagination"
|
||
:layout="tableConfig.layout"
|
||
:seqConfig="tableConfig.seqConfig"
|
||
:autoSize="tableConfig.autoSize"
|
||
:pageConfig="tableConfig.pageConfig"
|
||
class="block-table"
|
||
@table-row-click="rowClickEvent"
|
||
@size-change="pageSizeChange"
|
||
@current-page-change="currentChange"
|
||
>
|
||
<template
|
||
v-for="(colConfig, index) in tableConfig.colConfigs"
|
||
v-slot:[colConfig.customHeadSlot]="{ column }"
|
||
>
|
||
<div v-if="colConfig.customHeadSlot" :key="index">
|
||
{{ column }} {{ colConfig }}
|
||
</div>
|
||
</template>
|
||
<template
|
||
v-for="(colConfig, index) in tableConfig.colConfigs"
|
||
v-slot:[colConfig.customSlot]="{ row, rowIndex }"
|
||
>
|
||
<div v-if="colConfig.customSlot === 'options'" :key="index + '' + rowIndex">
|
||
<a
|
||
href="javascript:void(0)"
|
||
class="el-link el-link--primary"
|
||
@click.stop="handleRowDetail(row)"
|
||
>
|
||
查看
|
||
</a>
|
||
<span v-if="row.distributeStatus != '已分发' && hasEngineDataEditPermission()" class="link-separator"></span>
|
||
<a
|
||
v-if="row.distributeStatus != '已分发' && hasEngineDataEditPermission()"
|
||
href="javascript:void(0)"
|
||
class="el-link el-link--primary"
|
||
style="margin-left: 5px;"
|
||
@click.stop="handleRowDispatch(row, rowIndex)"
|
||
>
|
||
分发
|
||
</a>
|
||
<span v-if="row.distributeStatus === '未分发' && hasEngineDataEditPermission() && row.versionNumber === 1" class="link-separator"></span>
|
||
<a
|
||
v-if="row.distributeStatus === '未分发' && hasEngineDataEditPermission() && row.versionNumber === 1"
|
||
href="javascript:void(0)"
|
||
class="el-link el-link--primary"
|
||
style="margin-left: 5px;"
|
||
@click.stop="handleRowDelete(row, rowIndex)"
|
||
>
|
||
删除
|
||
</a>
|
||
</div>
|
||
<div v-if="colConfig.customSlot === 'distributeStatus'" :key="index + '' + rowIndex">
|
||
<span v-if="row[colConfig.prop] === '已分发'" class="status-tag status-done">
|
||
已分发
|
||
</span>
|
||
<span v-else-if="row[colConfig.prop] === '部分分发'" class="status-tag status-partial">
|
||
部分分发
|
||
</span>
|
||
<span v-else-if="row[colConfig.prop] === '未分发'" class="status-tag status-pending">
|
||
未分发
|
||
</span>
|
||
</div>
|
||
<div v-if="colConfig.customSlot === 'versionNumber'" :key="index + '' + rowIndex">
|
||
V{{ row[colConfig.prop] || '' }}
|
||
</div>
|
||
</template>
|
||
|
||
<template slot="empty">
|
||
<div class="table-empty">
|
||
<x-empty-page></x-empty-page>
|
||
</div>
|
||
</template>
|
||
</x-vxe-table>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 发动机详情组件 -->
|
||
<engine-detail
|
||
v-if="showEngineDetail"
|
||
:model="currentModel"
|
||
:engine-model-i-d="currentEngineModelID"
|
||
:is-dispatch-mode="isDispatchMode"
|
||
:dispatch-type="dispatchType"
|
||
:detail="currentEngineDetail"
|
||
class="engine-detail-wrapper"
|
||
@back="handleBackFromDetail"
|
||
/>
|
||
|
||
<!-- 添加机型弹窗 -->
|
||
<add-engine-model-modal ref="addEngineModelModal" @success="handleAddSuccess" />
|
||
|
||
<!-- 导入机型弹窗 -->
|
||
<el-dialog
|
||
title="导入机型"
|
||
:visible.sync="importDialogVisible"
|
||
width="400px"
|
||
append-to-body
|
||
@close="handleImportDialogClose"
|
||
>
|
||
<el-upload
|
||
class="import-uploader"
|
||
drag
|
||
:auto-upload="false"
|
||
:limit="1"
|
||
accept=".xls,.xlsx"
|
||
:file-list="importFileList"
|
||
:on-change="handleImportFileChange"
|
||
:on-remove="handleImportFileRemove"
|
||
>
|
||
<i class="el-icon-upload"></i>
|
||
<div class="el-upload__text">
|
||
将文件拖到此处,或<em>点击上传</em>
|
||
</div>
|
||
<div slot="tip" class="el-upload__tip">
|
||
仅支持Excel文件(.xlsx 或 .xls)
|
||
</div>
|
||
</el-upload>
|
||
<span slot="footer" class="dialog-footer">
|
||
|
||
<el-button @click="handleImportDialogClose">取消</el-button>
|
||
<el-button type="primary" :loading="importing" @click="handleImportConfirm">
|
||
开始导入
|
||
</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import EngineDetail from './engineDetail.vue'
|
||
import AddEngineModelModal from './add-engine-model-modal.vue'
|
||
import api from '@/api'
|
||
import { getUserId } from '@/utils'
|
||
const createDefaultSearch = () => ({
|
||
loginUserId: getUserId(),
|
||
modelName: '',
|
||
statusCode: '',
|
||
plate: '',
|
||
block: '',
|
||
platform: '',
|
||
series: '',
|
||
marketSegment: '',
|
||
projectName: '',
|
||
projectNumber: '',
|
||
distributeStatus: '',
|
||
ycOrOth: '竞品',
|
||
modelNameSimple: '',
|
||
productionDate: ''
|
||
})
|
||
|
||
export default {
|
||
name: 'SelfEngineData',
|
||
components: {
|
||
EngineDetail,
|
||
AddEngineModelModal
|
||
},
|
||
data: function() {
|
||
return {
|
||
searchPanelValue: createDefaultSearch(),
|
||
tableData: [],
|
||
pagination: { currentPage: 1, pageSize: 10, total: 0 },
|
||
showEngineDetail: false,
|
||
currentModel: '',
|
||
currentEngineModelID: '',
|
||
currentEngineDetail: null, // 当前机型的详情信息
|
||
isDispatchMode: false,
|
||
dispatchType: 'todo', // 分发类型:'todo' 表示分发责任人,'responsible' 表示分发填写人
|
||
importDialogVisible: false,
|
||
importing: false,
|
||
selectedImportFile: null,
|
||
importFileList: [],
|
||
downloadingTemplate: false
|
||
}
|
||
},
|
||
computed: {
|
||
tableConfig() {
|
||
return {
|
||
rowDraggable: false,
|
||
colConfigs: [
|
||
{
|
||
prop: 'modelName',
|
||
label: '产品型号',
|
||
showOverflowTooltip: true,
|
||
minWidth: '120'
|
||
},
|
||
{
|
||
prop: 'productNumber',
|
||
label: '状态代号',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'plate',
|
||
label: '板块',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'platform',
|
||
label: '平台',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'series',
|
||
label: '系列',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'marketSegment',
|
||
label: '细分市场',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'projectName',
|
||
label: '项目名称',
|
||
showOverflowTooltip: true,
|
||
minWidth: '120'
|
||
},
|
||
{
|
||
prop: 'projectNumber',
|
||
label: '项目编号',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100'
|
||
},
|
||
{
|
||
prop: 'parameterNum',
|
||
label: '标准参数',
|
||
showOverflowTooltip: true,
|
||
minWidth: '100',
|
||
align: 'center'
|
||
},
|
||
// {
|
||
// prop: 'maintainedParam',
|
||
// label: '已维护参数',
|
||
// showOverflowTooltip: true,
|
||
// minWidth: '110',
|
||
// align: 'center'
|
||
// },
|
||
{
|
||
prop: 'distributeStatus',
|
||
label: '任务分发状态',
|
||
customSlot: 'distributeStatus',
|
||
showOverflowTooltip: true,
|
||
minWidth: '120',
|
||
align: 'center'
|
||
},
|
||
{
|
||
prop: 'versionNumber',
|
||
label: '版本',
|
||
customSlot: 'versionNumber',
|
||
showOverflowTooltip: true,
|
||
minWidth: '80',
|
||
align: 'center'
|
||
},
|
||
{
|
||
prop: 'options',
|
||
label: '操作',
|
||
customSlot: 'options',
|
||
align: 'center',
|
||
width: '120',
|
||
fixed: 'right'
|
||
}
|
||
],
|
||
seqType: 'seq',
|
||
layout: 'total, prev, pager, next, sizes, jumper'
|
||
}
|
||
}
|
||
},
|
||
created() {
|
||
this.loadUserSelfRole()
|
||
this.loadData()
|
||
},
|
||
mounted() {
|
||
this.loadUserSelfRole()
|
||
this.loadData()
|
||
},
|
||
methods: {
|
||
// 检查是否是管理员(isAdmin === 1)
|
||
isAdmin() {
|
||
try {
|
||
const permissionDataStr = localStorage.getItem('user_self_role')
|
||
if (!permissionDataStr) {
|
||
return false
|
||
}
|
||
const permissionData = JSON.parse(permissionDataStr)
|
||
if (!Array.isArray(permissionData)) {
|
||
return false
|
||
}
|
||
// 检查是否有 isAdmin === 1 的记录
|
||
return permissionData.some((perm) => perm.isAdmin === 1 || perm.isAdmin === '1')
|
||
} catch (err) {
|
||
console.error('检查管理员权限失败:', err)
|
||
return false
|
||
}
|
||
},
|
||
// 检查是否有竞品发动机数据的编辑权限
|
||
hasEngineDataEditPermission() {
|
||
// 如果是管理员,拥有全部权限
|
||
if (this.isAdmin()) {
|
||
return true
|
||
}
|
||
try {
|
||
const permissionDataStr = localStorage.getItem('user_self_role')
|
||
if (!permissionDataStr) {
|
||
return false
|
||
}
|
||
const permissionData = JSON.parse(permissionDataStr)
|
||
if (!Array.isArray(permissionData)) {
|
||
return false
|
||
}
|
||
// 检查是否有 permissionPath 为 "竞品发动机数据" 且 parameterPer 是编辑的权限
|
||
// parameterPer 可能是数字 2 或字符串 "编辑" 或 "2"
|
||
return permissionData.some((perm) => {
|
||
const permissionPath = perm.permissionPath || ''
|
||
const parameterPer = perm.parameterPer
|
||
return (
|
||
permissionPath === '竞品发动机数据' &&
|
||
(parameterPer === 2 ||
|
||
parameterPer === '2' ||
|
||
parameterPer === '编辑')
|
||
)
|
||
})
|
||
} catch (err) {
|
||
console.error('检查竞品发动机数据编辑权限失败:', err)
|
||
return false
|
||
}
|
||
},
|
||
// 加载用户自身角色权限
|
||
loadUserSelfRole() {
|
||
const request = {
|
||
...api.GET_USER_SELF_ROLE,
|
||
params: {
|
||
userOrDepID: getUserId()
|
||
},
|
||
disableSuccessMsg: true
|
||
}
|
||
this.$request(request)
|
||
.asyncThen((resp) => {
|
||
if (resp && resp.data) {
|
||
// 将权限数据存储到 localStorage
|
||
try {
|
||
localStorage.setItem('user_self_role', JSON.stringify(resp.data))
|
||
} catch (err) {
|
||
console.error('存储权限数据到 localStorage 失败:', err)
|
||
}
|
||
}
|
||
})
|
||
.asyncErrorCatch((err) => {
|
||
console.error('获取用户自身角色失败:', err)
|
||
})
|
||
},
|
||
handleRowDispatch(row, rowIndex) {
|
||
// 跳转到详情页面,设置为分发模式(分发责任人)
|
||
this.currentModel = row.productFullName || ''
|
||
this.currentEngineModelID = row.id || row.rowId || row.engineModelID || ''
|
||
this.currentEngineDetail = row // 保存机型详情信息
|
||
this.isDispatchMode = true
|
||
this.dispatchType = 'todo' // 分发责任人
|
||
this.showEngineDetail = true
|
||
},
|
||
handleRowDelete(row, rowIndex) {
|
||
console.log(row, 'row')
|
||
const request = {
|
||
...api.DEL_ENGINE_MODEL,
|
||
params: {
|
||
modelId: row.id
|
||
},
|
||
disableSuccessMsg: true
|
||
}
|
||
this.$request(request)
|
||
.asyncThen((resp) => {
|
||
console.log(resp, 'resp')
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功'
|
||
})
|
||
this.loadData()
|
||
})
|
||
.asyncErrorCatch((err) => {
|
||
console.error('删除机型失败:', err)
|
||
this.$message({
|
||
type: 'error',
|
||
message: '删除失败'
|
||
})
|
||
})
|
||
},
|
||
pageSizeChange(size) {
|
||
this.pagination.pageSize = size
|
||
this.pagination.currentPage = 1
|
||
this.loadData()
|
||
},
|
||
rowClickEvent(row) {
|
||
console.warn(row)
|
||
},
|
||
handleRowDetail(row) {
|
||
this.currentModel = row.productFullName || ''
|
||
this.currentEngineModelID = row.id
|
||
this.currentEngineDetail = row // 保存机型详情信息
|
||
this.isDispatchMode = false
|
||
this.dispatchType = 'justCheck' // 查看模式,不影响分发类型
|
||
this.showEngineDetail = true
|
||
},
|
||
handleBackFromDetail() {
|
||
this.showEngineDetail = false
|
||
this.currentModel = ''
|
||
this.currentEngineModelID = ''
|
||
this.currentEngineDetail = null
|
||
this.isDispatchMode = false
|
||
this.dispatchType = 'todo'
|
||
},
|
||
currentChange(currentPage) {
|
||
this.pagination.currentPage = currentPage
|
||
console.log(this.pagination.currentPage, this.pagination.pageSize, 'currentPage')
|
||
|
||
this.loadData()
|
||
},
|
||
selectDataChange(data) {
|
||
this.$emit('select-data-change', data)
|
||
},
|
||
resetSearch() {
|
||
Object.assign(this.searchPanelValue, createDefaultSearch())
|
||
this.handleSearch()
|
||
},
|
||
handleSearch() {
|
||
this.loadData()
|
||
},
|
||
handleRefresh() {
|
||
this.pagination.currentPage = 1
|
||
this.handleSearch()
|
||
},
|
||
handleImport() {
|
||
if (this.importing) {
|
||
return
|
||
}
|
||
this.importDialogVisible = true
|
||
},
|
||
handleImportFileChange(uploadFile, uploadFiles) {
|
||
// 允许的文件类型
|
||
const allowedTypes = ['.xls', '.xlsx']
|
||
const allowedMimeTypes = [
|
||
'application/vnd.ms-excel',
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
'application/vnd.ms-excel.sheet.macroEnabled.12'
|
||
]
|
||
|
||
if (uploadFile && uploadFile.raw) {
|
||
const file = uploadFile.raw
|
||
const fileName = file.name || ''
|
||
const fileExtension = fileName.substring(fileName.lastIndexOf('.')).toLowerCase()
|
||
const fileType = file.type || ''
|
||
|
||
// 验证文件扩展名
|
||
const isValidExtension = allowedTypes.some(type => fileExtension === type)
|
||
// 验证 MIME 类型
|
||
const isValidMimeType = !fileType || allowedMimeTypes.some(type => fileType.includes(type))
|
||
|
||
if (!isValidExtension && !isValidMimeType) {
|
||
this.$message.error(`文件类型不支持,仅支持 ${allowedTypes.join('、')} 格式的文件`)
|
||
// 清空不符合要求的文件
|
||
this.selectedImportFile = null
|
||
this.importFileList = []
|
||
return false
|
||
}
|
||
|
||
this.selectedImportFile = file
|
||
this.importFileList = uploadFiles.slice(-1)
|
||
} else {
|
||
this.selectedImportFile = null
|
||
this.importFileList = uploadFiles.slice(-1)
|
||
}
|
||
},
|
||
handleImportFileRemove() {
|
||
this.selectedImportFile = null
|
||
this.importFileList = []
|
||
},
|
||
handleImportDialogClose() {
|
||
this.importDialogVisible = false
|
||
this.selectedImportFile = null
|
||
this.importFileList = []
|
||
},
|
||
handleImportConfirm() {
|
||
if (this.importing || !this.selectedImportFile) {
|
||
if (!this.selectedImportFile) {
|
||
this.$message.warning('请先选择要导入的文件')
|
||
}
|
||
return
|
||
}
|
||
|
||
const file = this.selectedImportFile
|
||
|
||
// 再次验证文件类型(双重保险)
|
||
const allowedTypes = ['.xls', '.xlsx']
|
||
const fileName = file.name || ''
|
||
const fileExtension = fileName.substring(fileName.lastIndexOf('.')).toLowerCase()
|
||
|
||
if (!allowedTypes.includes(fileExtension)) {
|
||
this.$message.error(`文件类型不支持,仅支持 ${allowedTypes.join('、')} 格式的文件`)
|
||
this.selectedImportFile = null
|
||
this.importFileList = []
|
||
return
|
||
}
|
||
|
||
const formData = new FormData()
|
||
formData.append('file', file)
|
||
formData.append('userId', getUserId())
|
||
formData.append('ycOrOt', '竞品')
|
||
|
||
const request = {
|
||
...api.IMPORT_ENGINE_MODEL_PARAM,
|
||
params: formData,
|
||
disableSuccessMsg: true
|
||
}
|
||
|
||
this.importing = true
|
||
// 显示全屏 loading 提示
|
||
const loadingInstance = this.$loading({
|
||
lock: true,
|
||
text: '正在导入机型,请稍候...',
|
||
spinner: 'el-icon-loading',
|
||
background: 'rgba(0, 0, 0, 0.7)'
|
||
})
|
||
this.$upload(request, null, false)
|
||
.then((resp) => {
|
||
console.log('导入成功:', resp)
|
||
loadingInstance.close()
|
||
// 导入成功后刷新列表
|
||
this.handleImportDialogClose()
|
||
this.loadData()
|
||
})
|
||
.catch((err) => {
|
||
console.error('导入失败:', err)
|
||
loadingInstance.close()
|
||
this.$message.error('导入失败,请稍后重试')
|
||
})
|
||
.finally(() => {
|
||
// 确保 loading 在所有情况下都能关闭
|
||
if (loadingInstance) {
|
||
loadingInstance.close()
|
||
}
|
||
this.importing = false
|
||
})
|
||
},
|
||
handleDownloadTemplate() {
|
||
if (this.downloadingTemplate) {
|
||
return
|
||
}
|
||
const { url, method = 'get', headers = {} } = api.DOWNLOAD_ENGINE_DEMO || {}
|
||
const requestConfig = {
|
||
url,
|
||
method,
|
||
params: {},
|
||
responseType: 'blob',
|
||
headers
|
||
}
|
||
if (!requestConfig.url) {
|
||
console.log('未配置下载地址')
|
||
return
|
||
}
|
||
if ((requestConfig.method || '').toLowerCase() === 'post') {
|
||
requestConfig.data = requestConfig.params
|
||
delete requestConfig.params
|
||
}
|
||
const defaultFilename = '机型导入模板.xlsx'
|
||
this.downloadingTemplate = true
|
||
this.$axios(requestConfig)
|
||
.then((response) => {
|
||
const blobData = response.data
|
||
if (!blobData) {
|
||
console.log('下载失败,文件内容为空')
|
||
return
|
||
}
|
||
const contentType =
|
||
response.headers &&
|
||
(response.headers['content-type'] || response.headers['Content-Type'])
|
||
if (contentType && contentType.includes('application/json')) {
|
||
try {
|
||
const reader = new FileReader()
|
||
reader.onload = () => {
|
||
console.log(`下载失败: ${reader.result}`)
|
||
}
|
||
reader.readAsText(blobData)
|
||
} catch (err) {
|
||
console.error('解析下载失败响应异常:', err)
|
||
}
|
||
return
|
||
}
|
||
const disposition =
|
||
response.headers &&
|
||
(response.headers['content-disposition'] || response.headers['Content-Disposition'])
|
||
let filename = defaultFilename
|
||
if (disposition) {
|
||
const filenameMatch = /filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i.exec(
|
||
disposition
|
||
)
|
||
const matchedName = filenameMatch ? filenameMatch[1] || filenameMatch[2] : ''
|
||
if (matchedName) {
|
||
try {
|
||
filename = decodeURIComponent(matchedName)
|
||
} catch (err) {
|
||
filename = matchedName
|
||
}
|
||
}
|
||
}
|
||
const downloadUrl = window.URL.createObjectURL(blobData)
|
||
const link = document.createElement('a')
|
||
link.href = downloadUrl
|
||
link.download = filename
|
||
document.body.appendChild(link)
|
||
link.click()
|
||
document.body.removeChild(link)
|
||
window.URL.revokeObjectURL(downloadUrl)
|
||
this.$message({
|
||
type: 'success',
|
||
message: '下载成功'
|
||
})
|
||
console.log('下载开始,请查看浏览器下载列表')
|
||
})
|
||
.catch((err) => {
|
||
console.error('下载失败:', err)
|
||
this.$message.error('下载失败,请稍后重试')
|
||
})
|
||
.finally(() => {
|
||
this.downloadingTemplate = false
|
||
})
|
||
},
|
||
handleAdd() {
|
||
// 从 selfEnginedata.vue 跳转,设置 ycOrOth 为 "竞品"
|
||
this.$refs.addEngineModelModal.showModal('竞品')
|
||
},
|
||
handleAddSuccess() {
|
||
// 子组件已经关闭弹窗,这里只需要刷新列表
|
||
this.loadData()
|
||
},
|
||
loadData() {
|
||
const request = {
|
||
...api.GET_ENGINE_LIST_SELF,
|
||
params: {
|
||
page: this.pagination.currentPage,
|
||
size: this.pagination.pageSize,
|
||
ycOrOth: '竞品',
|
||
...this.searchPanelValue
|
||
},
|
||
disableSuccessMsg: true
|
||
}
|
||
console.log(this.pagination.currentPage, this.pagination.pageSize, 'request')
|
||
|
||
this.$request(request)
|
||
.asyncThen((resp) => {
|
||
this.tableData = resp.data.list
|
||
this.pagination.total = resp.data.totalCount
|
||
})
|
||
.asyncErrorCatch((err) => {
|
||
console.error('查询失败:', err)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.custom-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.page-header {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 56px;
|
||
position: relative;
|
||
width: 100%;
|
||
min-height: 56px;
|
||
background: #fff;
|
||
border-bottom: 1px solid #ebeef5;
|
||
overflow: auto;
|
||
|
||
.title {
|
||
color: #303133;
|
||
font-weight: 700;
|
||
margin-left: 20px;
|
||
flex: 1;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.operation {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-right: 20px;
|
||
|
||
.import-button {
|
||
background: #fff;
|
||
border: 1px solid #409eff;
|
||
color: #409eff;
|
||
padding: 8px 16px;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
|
||
&:hover {
|
||
background: #b3d8ff;
|
||
border-color: #66b1ff;
|
||
color: #409eff;
|
||
}
|
||
|
||
&:active {
|
||
background: #409eff;
|
||
color: white;
|
||
}
|
||
}
|
||
|
||
.add-button {
|
||
padding: 8px 16px;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.page-data-list {
|
||
display: flex;
|
||
padding: 20px;
|
||
|
||
.x-empty-page {
|
||
top: 0;
|
||
}
|
||
}
|
||
|
||
.status-tag {
|
||
display: inline-block;
|
||
padding: 2px 8px;
|
||
border-radius: 2px;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
|
||
&.status-done {
|
||
background: #67c23a;
|
||
color: white;
|
||
}
|
||
|
||
&.status-partial {
|
||
background: #e6a23c;
|
||
color: white;
|
||
}
|
||
|
||
&.status-pending {
|
||
background: #f5f7fa;
|
||
color: #606266;
|
||
}
|
||
}
|
||
|
||
.engine-detail-wrapper {
|
||
width: 100%;
|
||
height: 100%;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.import-uploader {
|
||
width: 100%;
|
||
.el-upload {
|
||
width: 100%;
|
||
}
|
||
.el-upload-dragger {
|
||
width: 100%;
|
||
}
|
||
}
|
||
}
|
||
.page-search-panel {
|
||
background: white;
|
||
padding: 16px 24px !important;
|
||
border-bottom: 1px solid #ebeef5 !important;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column !important;
|
||
gap: 16px;
|
||
|
||
.search-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
|
||
::v-deep .el-button {
|
||
padding: 0 16px;
|
||
font-size: 14px;
|
||
border-radius: 4px;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
}
|
||
}
|
||
}
|
||
.searched-fields {
|
||
max-height: 200px !important;
|
||
display: flex !important;
|
||
flex-wrap: wrap !important;
|
||
flex-direction: row !important;
|
||
gap: 16px 32px !important;
|
||
width: 100% !important;
|
||
}
|
||
.searched-field {
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
gap: 12px !important;
|
||
flex: 1 1 calc((100% - 96px) / 4) !important;
|
||
// min-width: 160px !important;
|
||
max-width: calc(25% - 32px) !important;
|
||
.fielded-label {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
white-space: nowrap;
|
||
min-width: 80px !important;
|
||
text-align: right;
|
||
text-align-last: right;
|
||
text-justify: inter-ideograph;
|
||
}
|
||
|
||
.el-input,
|
||
.el-select {
|
||
width: 170px;
|
||
}
|
||
|
||
::v-deep .el-input__inner,
|
||
::v-deep .el-select .el-input__inner {
|
||
height: 32px;
|
||
line-height: 32px;
|
||
}
|
||
}
|
||
.link-separator {
|
||
width: 4px;
|
||
height: 14px;
|
||
}
|
||
::v-deep .el-button {
|
||
line-height: 0.85 !important;
|
||
}
|
||
</style>
|