Initial commit

This commit is contained in:
danshihao
2024-06-11 15:39:01 +08:00
commit 00acf31aa3
1589 changed files with 520803 additions and 0 deletions
@@ -0,0 +1,523 @@
<template>
<div class="detail-page">
<a-spin :spinning="loading">
<div class="detail-page-title">{{ pageTitle }}{{ $t('details') }}</div>
<div class="detail-page-part" v-for="(part, index) in partList" :key="part + index">
<div class="detail-page-part-title">
<span>{{ part }}</span>
<div class="detail-page-part-title-operate-box" v-if="index === 0">
<!-- 更新记录-->
<a-button type="link" @click="handleOpenUpdateRecord" v-has="btnPermission.updateRecord">
<i class="iconfont icon-root-list" />
{{ $t('standardRegulationLibrary.updateRecord') }}
</a-button>
<!-- 提交问题-->
<a-button type="link" @click="submitQuestion" v-has="btnPermission.submitQuestion">
<a-icon type="database" />
{{ $t('standardRegulationLibrary.submitQuestion') }}
</a-button>
<!-- 分享-->
<a-button type="link" @click="handleShare" v-has="btnPermission.share">
<i class="iconfont icon-share-internal" />{{ $t('share') }}
</a-button>
</div>
</div>
<div class="detail-page-part-form" v-if="part !== '过程稿件' && part !== 'Process Manuscript'">
<div class="detail-page-part-form-item" v-for="formItem in form[part]" :key="formItem.id">
<label>{{ formItem.dbFieldTxt }}</label>
<!--标准需要跳转是标准字段且有内容的情况下在这处理-->
<template v-if="standardFields.includes(formItem.dbFieldName) && !!detailData[formItem.dbFieldName]">
<div class="div-form-content">
<template v-for="(standard, standardIndex) in detailData[formItem.dbFieldName].split(',')">
<div class="can-click" :key="'standardKey' + standardIndex" @click="toStandardDetailPage(standard)">{{ standard }}</div>
<div v-if="standardIndex!==detailData[formItem.dbFieldName].split(',').length - 1">,</div>
</template>
</div>
</template>
<!--文件需要显示预览-->
<div class="file-box" v-else-if="fileField.includes(formItem.dbFieldName)">
<template v-if="detailData[formItem.dbFieldName + 'List'] && detailData[formItem.dbFieldName + 'List'].length > 0">
<div class="detail-page-process-manuscript-file"
v-for="file in detailData[formItem.dbFieldName + 'List']"
:key="file.id">
<div class="detail-page-process-manuscript-file-info">
<a-icon type="link" />
<div class="detail-page-process-manuscript-file-name" @click="handlePreview(file)">{{ file.fileName }}</div>
</div>
<!-- 下载-->
<a-button type="link"
icon="download"
v-has="btnPermission.download"
class="file-btn"
@click="handleDownload(file)">
{{
$t('download')
}}
</a-button>
<!-- 无水印下载-->
<!--<a-button type="link" v-has="btnPermission.unwatermarkedDownload" class="file-btn">-->
<!-- <i class="iconfont icon-water-drop-slash"></i>-->
<!-- {{ $t('unwatermarkedDownload') }}-->
<!--</a-button>-->
</div>
</template>
<span v-else>{{ global.emptyLine }}</span>
</div>
<!-- 需要显示查看全部按钮 -->
<a-button v-else-if="showViewAllField.includes(formItem.dbFieldName) &&
(detailData[formItem.dbFieldName + '_dictText'] || detailData[formItem.dbFieldName])"
type="primary" ghost @click="viewAll(formItem.dbFieldName)">
{{ $t('enterpriseStandardLibrary.standard.viewAll')}}
</a-button>
<span v-else>
{{
detailData[needDictFieldList.includes(formItem.fieldShowType) ? formItem.dbFieldName + '_dictText' : formItem.dbFieldName] || global.emptyLine
}}
</span>
</div>
</div>
<!-- 过程稿件特殊处理-->
<div class="detail-page-process-manuscript" v-if="part === '过程稿件' || part === 'Process Manuscript'">
<div class="detail-page-process-manuscript-item" v-for="formItem in form[part]" :key="formItem.id">
<div class="detail-page-process-manuscript-title">
<span>{{ formItem.dbFieldTxt }}</span>
<!-- 标准分解单-->
<a-button type="primary"
ghost
icon="file-text"
@click="previewStandardResolutionSheet(detailData[formItem.dbFieldName + '_standardSplit'])"
v-has="btnPermission.standardResolutionSheet"
:disabled="!detailData[formItem.dbFieldName + '_standardSplit']">
{{ $t('standardRegulationLibrary.standardResolutionSheet') }}
</a-button>
</div>
<div class="detail-page-process-manuscript-file"
v-for="file in detailData[formItem.dbFieldName + 'List']"
:key="file.id">
<div class="detail-page-process-manuscript-file-info">
<a-icon type="link" />
<div class="detail-page-process-manuscript-file-name" @click="handlePreview(file)">{{ file.fileName }}</div>
</div>
<div class="detail-page-process-manuscript-file-operate">
<!-- 下载-->
<a-button type="link" icon="download" v-has="btnPermission.download" @click="handleWatermarkedDownload(file)">
{{ $t('download') }}
</a-button>
<!-- 无水印下载-->
<a-button type="link" v-has="btnPermission.unwatermarkedDownload" @click="handleDownload(file)">
<i class="iconfont icon-water-drop-slash"></i>
{{ $t('unwatermarkedDownload') }}
</a-button>
</div>
</div>
</div>
</div>
</div>
</a-spin>
<div id="images">
<div class="image" v-viewer="{movable: false}">
<img v-show="image" :src="imageUrl" alt="">
</div>
</div>
<!-- 更新记录-->
<update-record-modal ref="uploadRecordModal" />
<!-- 提交问题-->
<submit-question-modal ref="submitQuestionModal" />
<!-- 分享选人-->
<user-select-modal ref="userSelectModal" type="checkbox" @change="continueShare" />
<!-- 标准分解单-->
<standard-resolution-sheet-modal ref="standardResolutionSheetModal" />
<!-- 查看全部弹框 -->
<text-content-modal ref="textContentModal"></text-content-modal>
</div>
</template>
<script>
import '@assets/less/common.less'
import { FieldType, StandardSource } from '../../../enums/commonEnums'
import {
getDomesticStandardFormModal,
shareDomesticStandard,
getDomesticStandardDetail,
getOverseasStandardForm,
getOverseasStandardDocumentInfo,
shareOverseasStandard
} from '../../../api/standardRegulationLibraryApi'
import UpdateRecordModal from './modules/UpdateRecordModal.vue'
import SubmitQuestionModal from './modules/SubmitQuestionModal.vue'
import UserSelectModal from '../../../components/selection/UserSelectModal.vue'
import StandardResolutionSheetModal from './modules/StandardResolutionSheetModal.vue'
import { getFileInfo } from '../../../api/api.js'
import Vue from 'vue'
import { ACCESS_TOKEN } from '../../../store/mutation-types.js'
import { downloadFile, getFileAccessHttpUrl } from '../../../api/manage.js'
import { previewPdf } from '../../../utils/previewPdf.js'
import { Base64 } from 'js-base64'
import { kkFilePreview } from '../../../utils/kkFilePreview'
import { previewFileCurrentWindowByFileId, queryStandardInfoByStandardNumber } from '../../../utils/util'
import TextContentModal from '../../enterpriseStandardLibrary/standard/detail/module/TextContentModal'
// 国内标准权限
const DomesticStandardPermission = {
updateRecord: 'domesticStandard:updateRecord', // 更新记录
submitQuestion: 'domesticStandard:submitQuestion', // 提交问题
share: 'domesticStandard:share', // 分享
standardResolutionSheet: 'domesticStandard:standardResolutionSheet', // 标准分解单
download: 'domesticStandard:download', // 下载
unwatermarkedDownload: 'domesticStandard:unwatermarkedDownload' // 无水印下载
}
// 海外标准权限
const OverseasStandardPermission = {
updateRecord: 'overseasStandard:updateRecord', // 更新记录
submitQuestion: 'overseasStandard:submitQuestion', // 提交问题
share: 'overseasStandard:share', // 分享
standardResolutionSheet: 'overseasStandard:standardResolutionSheet', // 标准分解单
download: 'overseasStandard:download', // 下载
unwatermarkedDownload: 'overseasStandard:unwatermarkedDownload' // 无水印下载
}
// 国内标准接口
const DomesticApi = {
getFormFunc: getDomesticStandardFormModal, // 获取字段
getDetailData: getDomesticStandardDetail, // 获取详情数据
share: shareDomesticStandard // 分享
}
// 海外标准接口
const OverseasApi = {
getFormFunc: getOverseasStandardForm, // 获取字段
getDetailData: getOverseasStandardDocumentInfo, // 获取详情数据
share: shareOverseasStandard // 分享
}
// 支持预览的文件后缀
const CAN_PREVIEW_FILE_SUFFIX = ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx']
const FILE_TYPE_PDF = 'pdf'
const FILE_TYPE_IMGS = ['jpg', 'jpeg', 'png', 'raw']
export default {
name: 'StandardDetailPage',
components: { UpdateRecordModal, SubmitQuestionModal, UserSelectModal, StandardResolutionSheetModal, TextContentModal },
data () {
return {
loading: false,
partList: [], // 页面模块列表
form: {}, // 页面字段
// 页面数据
detailData: {},
// 文件的字段
fileField: [],
// 需要数据字段翻译的属性类型
needDictFieldList: [FieldType.USER_SINGLE.value, FieldType.ORGAN_SINGLE.value, FieldType.ORGAN_MORE.value, FieldType.OPTION_SINGLE.value, FieldType.OPTION_MORE.value, FieldType.TREE.value, FieldType.TREE_SINGLE.value],
image: false,
imageUrl: null,
// 标准字段,需要跳转标准详情
standardFields: ['substitute_standard_number', 'replaced_by_standard_number', 'reference_standard', 'referenced_standard', 'adopt_the_international_standard_number', 'associated_foreign_standards'],
showViewAllField: ['auth_dept'] // 需要显示展示查看全部按钮的字段
}
},
computed: {
type () {
if (this.$route.path.indexOf('Domestic') !== -1) {
return StandardSource.DOMESTIC.value
}
if (this.$route.path.indexOf('Overseas') !== -1) {
return StandardSource.OVERSEAS.value
}
return ''
},
pageTitle () {
if (this.type === StandardSource.DOMESTIC.value) {
return this.$t('system.tag.domesticLaws')
}
if (this.type === StandardSource.OVERSEAS.value) {
return this.$t('system.tag.foreignStandards')
}
return ''
},
// 按钮权限
btnPermission () {
let permission = {}
switch (this.type) {
// 国内标准法规
case StandardSource.DOMESTIC.value:
permission = DomesticStandardPermission
break
// 海外
case StandardSource.OVERSEAS.value:
permission = OverseasStandardPermission
break
default:
break
}
return permission
},
// 操作接口
operateApiFunc () {
let func = {}
switch (this.type) {
case StandardSource.DOMESTIC.value:
func = DomesticApi
break
case StandardSource.OVERSEAS.value:
func = OverseasApi
break
default:
break
}
return func
}
},
async created () {
// 如果是要直接看文件
// if (this.$route.query.viewFile) {
// // TODO 这里需要调一个接口,通过标准id按规则获取文件
// const fileId = '1734843741558288385'
// previewFileCurrentWindowByFileId(fileId).then(() => {
// }).catch((message) => {
// this.$message.warning(message)
// })
// return
// }
await this.initForm()
this.initDetailData()
},
methods: {
/**
* 获取页面字段
*/
initForm () {
return new Promise(resolve => {
this.operateApiFunc.getFormFunc({ type: 1 }).then(res => {
if (res.success) {
const data = res.result || {}
this.partList = Object.keys(data)
const formList = Object.values(data).reduce((acc, cur) => acc.concat(cur), [])
this.fileField = []
formList.forEach(item => {
if (item.fieldShowType === FieldType.FILE_UP.value) {
this.fileField.push(item.dbFieldName)
}
})
this.form = data
} else {
this.$message.warn(res.message)
}
}).finally(() => {
resolve()
})
})
},
// 获取数据
initDetailData () {
this.loading = true
this.operateApiFunc.getDetailData({ id: this.$route.query.id, type: 1 }).then(res => {
if (res.success) {
this.detailData = Object.assign({}, res.result || {})
this.fileField.forEach(item => {
if (this.detailData[item]) {
const fileList = this.detailData[item].split(',')
const fileInfoList = []
fileList.forEach(async id => {
const fileInfo = await this.getFileInfo(id)
if (fileInfo) {
fileInfoList.push(fileInfo)
}
})
this.$set(this.detailData, item + 'List', fileInfoList)
}
})
console.log(this.detailData)
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
getFileInfo (fileId) {
return new Promise(resolve => {
let fileInfo
getFileInfo({ id: fileId }).then(res => {
if (res.success) {
fileInfo = res.result
}
}).finally(() => {
resolve(fileInfo)
})
})
},
/**
* 更新记录
*/
handleOpenUpdateRecord () {
this.$refs.uploadRecordModal.open(this.detailData.standard_number)
},
/**
* 提交问题
*/
submitQuestion () {
this.$refs.submitQuestionModal.open(this.detailData.standard_number, this.type)
},
/**
* 分享
*/
handleShare () {
this.$refs.userSelectModal.open()
},
/**
* 选择分享的人之后继续分享
* @param ids
*/
continueShare (ids) {
const params = {
standardId: this.$route.query.id, // 要分享的标准的id
standardNumber: this.detailData.standard_number, // 分享的标准编号
recipientId: ids // 分享给的用户的id
}
this.loading = true
this.operateApiFunc.share(params).then(res => {
if (res.success) {
this.$message.success(res.message)
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
/**
* 查看标准分解单
*/
previewStandardResolutionSheet (id) {
this.$refs.standardResolutionSheetModal.open(id)
},
// 查看全部
viewAll (fieldName) {
const data = this.detailData[fieldName + '_dictText'] || this.detailData[fieldName]
this.$refs.textContentModal.open(data)
},
handlePreview (file) {
if (!file || !file.url) {
return
}
// 截取文件后缀名
const fileSuffix = file.fileName ? file.fileName.split('.')[file.fileName.split('.').length - 1] : ''
const canPreview = CAN_PREVIEW_FILE_SUFFIX.some(tt => fileSuffix.toLowerCase() === tt)
// 判断是否为可预览格式的文件
if (!canPreview) {
this.$message.loading('该文件类型不支持预览,正在为您准备下载...').then(() => {
this.handleDownload(file)
})
return
}
const fileFullUrl = `${window._CONFIG.domianWebSocketURL}/sys/common/view/${file.id}?at=${Vue.ls.get(ACCESS_TOKEN)}&fullfilename=${file.fileName}`
console.log(fileFullUrl)
// 图片预览,使用自己添加的组件
if (canPreview && FILE_TYPE_IMGS.includes(fileSuffix.toLowerCase())) {
this.imageUrl = getFileAccessHttpUrl(file.id)
// 获取viewer实例
const viewer = this.$el.querySelector('.image').$viewer
// 调用show方法进行显示预览图
viewer.show()
// this.$refs.imagePreviewModal.open(file)
return
}
// pdf预览
if (canPreview && FILE_TYPE_PDF.includes(fileSuffix.toLowerCase())) {
const url = previewPdf(file.id)
window.open(url)
return
}
// 其余可预览文件仍使用KKFile进行预览
kkFilePreview(fileFullUrl)
},
/**
* 无水印下载
* @param file
*/
handleDownload (file) {
// 下载文件
downloadFile(`/sys/common/noEncryptDownloadWithoutWaterMark/${file.id}`, file.fileName)
},
/**
* 有水印下载
* @param file
*/
handleWatermarkedDownload (file) {
downloadFile(`/sys/common/noEncryptDownload/${file.id}`, file.fileName)
},
async toStandardDetailPage (standardNumber) {
const standardInfo = await queryStandardInfoByStandardNumber(standardNumber)
if (!standardInfo) {
return
}
let path
// 根据来源跳转不同的详情页
switch (standardInfo.source) {
// 国内
case StandardSource.DOMESTIC.value:
path = '/standardRegulationLibrary/DomesticStandardDetail'
break
// 海外
case StandardSource.OVERSEAS.value:
path = '/standardRegulationLibrary/OverseasStandardDetail'
break
// 企标
case StandardSource.ENTERPRISE.value:
path = '/enterpriseStandardLibrary/enterpriseStandardDetail'
break
default:
break
}
if (!path) {
return
}
const query = {
id: standardInfo.id
}
this.$openPageNewSheet({
path, query
})
}
}
}
</script>
<style scoped lang="less">
.file-box {
flex: 1;
width: 0;
}
.file-btn > ::v-deep span {
display: inline;
color: @primary-color;
font-size: 14px;
}
.div-form-content {
word-break: break-all;
white-space: pre-wrap;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
color: #1D2129;
-ms-flex: 1;
flex: 1;
width: 0;
}
.div-form-content > div {
display: inline-block;
}
.can-click {
display: inline-block;
color: @primary-color;
cursor: pointer;
}
</style>
@@ -0,0 +1,84 @@
<template>
<j-modal
:title="$t('standardRegulationLibrary.standardResolutionSheet')"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
fullscreen
switchFullscreen
@cancel="handleCancel">
<a-spin :spinning="confirmLoading">
<div class="page-container">
<standard-resolution-sheet ref="resolutionSheet" />
</div>
</a-spin>
<template v-slot:footer>
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import StandardResolutionSheet from '../../../../components/StandardResolutionSheet.vue'
export default {
name: 'StandardResolutionSheetModal',
components: { StandardResolutionSheet },
data () {
return {
width: '90%',
visible: false,
confirmLoading: false,
splitId: null,
isFullScreen: false
}
},
methods: {
open (id) {
this.visible = true
this.$nextTick(() => {
const ids = id.split(',')
this.$refs.resolutionSheet.queryParams = {
id: ids[0],
publishBeforeId: ids[1]
}
this.$refs.resolutionSheet.initClauseFieldList()
this.$refs.resolutionSheet.initDetailInfo()
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
.page-container {
min-height: 250px;
height: calc(100vh - 200px - 55px - 54px - 48px);
}
/deep/ .ant-modal-body {
background: #F0F2F4;
}
// 处理全屏状态下的样式问题
.j-modal-box.fullscreen .ant-modal-content .ant-modal-body {
.ant-spin-nested-loading {
height: 100%;
/deep/ .ant-spin-container {
height: 100%;
}
}
.page-container {
height: 100%;
}
}
</style>
@@ -0,0 +1,202 @@
<template>
<j-modal
:title="$t('standardRegulationLibrary.submitQuestion')"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<a-row :gutter="24">
<a-col :span="12">
<!-- 标题-->
<a-form-item :label="$t('title')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('title')"
:maxLength="50"
v-decorator="['title', validatorRules.title]" />
</a-form-item>
</a-col>
<a-col :span="12">
<!-- 项目-->
<a-form-item :label="$t('project')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-select :placeholder="$t('pleaseSelect') + $t('project')"
v-decorator="['project', validatorRules.project]"
show-search
:filter-option="filterOption">
<a-select-option v-for="item in projectSelectOptions" :key="item.id" :title="item.projectName">{{ item.projectName }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<!-- 标准编号-->
<a-form-item :label="$t('standardRegulationLibrary.standardDetail.standardNumber')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('standardRegulationLibrary.standardDetail.standardNumber')"
:maxLength="50"
disabled
v-decorator="['standardNumber', validatorRules.standardNumber]" />
</a-form-item>
</a-col>
<a-col :span="12">
<!-- 提问时间-->
<a-form-item :label="$t('standardRegulationLibrary.standardDetail.problemOccurrenceTime')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-date-picker :placeholder="$t('pleaseSelect') + $t('standardRegulationLibrary.standardDetail.problemOccurrenceTime')"
:getCalendarContainer="(trigger) => trigger.parentNode"
v-decorator="['quizTime', validatorRules.quizTime]"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
showTime
style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="24">
<!-- 问题描述-->
<a-form-item :label="$t('standardRegulationLibrary.standardDetail.problemDescription')"
:labelCol="longLabelCol"
:wrapperCol="longWrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('standardRegulationLibrary.standardDetail.problemDescription')"
type="textarea"
:maxLength="500"
v-decorator="['problemDescription', validatorRules.problemDescription]" />
<j-upload v-decorator="['file', validatorRules.file]" return-id multiple />
</a-form-item>
</a-col>
</a-row>
</a-form>
</j-modal>
</template>
<script>
import { submitDomesticQuestion, submitOverseasQuestion } from '../../../../api/standardRegulationLibraryApi.js'
import { getCarTypeProjectList } from '../../../../api/projectLibraryApi.js'
import { StandardSource } from '../../../../enums/commonEnums.js'
import moment from 'moment'
export default {
name: 'SubmitQuestionModal',
data () {
return {
width: 800,
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
modal: {},
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
longLabelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
longWrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 标题
title: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('title') }],
validateTrigger: 'blur'
},
// 项目
project: {
rules: [{ required: false, message: this.$t('pleaseSelect') + this.$t('project') }],
validateTrigger: 'change'
},
// 标准编号
standardNumber: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('standardRegulationLibrary.standardDetail.standardNumber') }],
validateTrigger: 'blur'
},
// 问题发生时间
quizTime: {
rules: [{ required: false, message: this.$t('pleaseSelect') + this.$t('standardRegulationLibrary.standardDetail.problemOccurrenceTime') }],
validateTrigger: 'change'
},
// 问题描述
problemDescription: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('standardRegulationLibrary.standardDetail.problemDescription') }],
validateTrigger: 'blur'
},
// 附件
file: {},
type: null
},
projectSelectOptions: [] // 项目下拉数据
}
},
methods: {
open (standardNumber, type) {
this.visible = true
this.initProjectOptions()
this.type = type
const param = {}
param.standardNumber = standardNumber
param.quizTime = moment().format('YYYY-MM-DD HH:mm:ss')
this.$nextTick(() => {
this.form.setFieldsValue(param)
})
},
// 获取项目下拉框数据
initProjectOptions () {
getCarTypeProjectList({ column: 'createTime', order: 'desc' }).then(res => {
if (res.success) {
this.projectSelectOptions = res.result
} else {
this.$message.warning(res.message)
}
})
},
handleOk () {
if (this.confirmLoading) return
this.form.validateFields((err, values) => {
if (!err) {
let submitFunc
switch (this.type) {
case StandardSource.DOMESTIC.value:
submitFunc = submitDomesticQuestion
break
case StandardSource.OVERSEAS.value:
submitFunc = submitOverseasQuestion
break
default:
break
}
this.confirmLoading = true
const param = Object.assign({}, values)
submitFunc(param).then(res => {
if (res.success) {
this.$message.success(res.message)
this.close()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
},
filterOption (input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,76 @@
<template>
<j-modal
:title="$t('standardRegulationLibrary.updateRecord')"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@cancel="handleCancel">
<a-spin :spinning="confirmLoading">
<template v-if="recordList && recordList.length > 0">
<div class="record-item" v-for="record in recordList" :key="record.id">
{{ record.content }}
</div>
</template>
<a-empty v-else/>
</a-spin>
<template v-slot:footer>
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import { getDomesticStandardUpdateRecord } from '../../../../api/standardRegulationLibraryApi.js'
export default {
name: 'UpdateRecordModal',
data () {
return {
width: 800,
visible: false,
confirmLoading: false,
recordList: []
}
},
methods: {
open (standardNumber) {
this.visible = true
this.initRecord(standardNumber)
},
initRecord (standardNumber) {
this.confirmLoading = true
getDomesticStandardUpdateRecord({ standardNumber }).then(res => {
if (res.success) {
this.recordList = res.result || []
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
.record-item {
padding: 20px 0;
border-bottom: 1px solid #E5E6EB;
}
.record-item:first-child {
padding-top: 0;
}
.record-item:last-child {
border-bottom: none;
}
</style>
@@ -0,0 +1,825 @@
<template>
<a-card :bordered="false" class="page-left-right-layout">
<!-- 树部分-->
<div class="page-left-box">
<a-input-search v-model="treeInput" class="tree-search"
:placeholder="$t('standardRegulationLibrary.domesticStandard.treeSearchPlaceholder')"
@search="handleTreeSearch" />
<div class="page-tree-box page-tree-box-has-search">
<a-spin :spinning="treeLoading">
<a-tree :show-line="true"
:show-icon="true"
:tree-data="treeData"
:expanded-keys.sync="expandedKeys"
:selected-keys="selectedTreeKeys">
<template #title="record">
<div class="tree-operate-node"
@mouseenter="handleTreeMouseover(record.key)"
@mouseleave="handleTreeMouseout(record.key)"
@click="handleSelectTreeNode(record)">
<a-icon class="parent-node-icon"
type="folder"
v-if="record.dataRef.children && record.dataRef.children.length > 0" />
<a-tooltip>
<template #title>
{{ record.title }}
</template>
<span class="tree-node-custom-title">{{ record.title }}</span>
</a-tooltip>
<div class="tree-operate-node-btn-box" :class="{'tree-operate-node-btn-box-hide': record.key !== mouseInNodeKey}">
<!-- 新增-->
<a-button icon="plus"
class="tree-operate-node-btn"
@click.stop="handleAddTreeNode(record)"
v-if="record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value"
v-has="'domesticStandard:tree:add'"></a-button>
<!-- 编辑根节点不能编辑-->
<a-button class="tree-operate-node-btn"
@click.stop="handleEditTreeNode(record)"
v-has="'domesticStandard:tree:edit'"
v-if="record.nodeType !== StandardSystemTreeNodeType.ROOT_NODE.value && record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value">
<i class="iconfont icon-bianji" />
</a-button>
<!-- 删除根节点不能删除-->
<a-button class="tree-operate-node-btn"
v-has="'domesticStandard:tree:delete'"
v-if="record.nodeType !== StandardSystemTreeNodeType.ROOT_NODE.value && record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value"
@click.stop="handleDelTreeNode(record)">
<i class="iconfont icon-shanchu_" />
</a-button>
</div>
</div>
</template>
</a-tree>
</a-spin>
</div>
</div>
<!-- 表格部分-->
<div class="page-right-box">
<div class="table-page-search-wrapper">
<search ref="searchRef"
:url="url"
:get-query-condition-func="getQueryConditionFunc"
:defaultSearchParams="defaultSearchParams"
search-has="domesticStandard:search"
@search="searchQuery"
@reset="searchReset" />
</div>
<div class="table-operator">
<!-- 新增-->
<a-button icon="plus" type="primary" @click="handleAdd" v-has="'domesticStandard:add'">{{ $t('newlyAdded') }}</a-button>
<!-- 导入-->
<a-upload name="file"
:showUploadList="false"
:multiple="false"
:headers="tokenHeader"
:action="importExcelUrl"
v-has="'domesticStandard:import'"
@change="handleImportExcel">
<a-button type="primary" icon="download" ghost>{{ $t('import') }}</a-button>
</a-upload>
<!-- 导出-->
<a-button icon="upload"
type="primary"
ghost
v-has="'domesticStandard:export'"
@click="handleExportXls($t('standardRegulationLibrary.domesticStandard.exportFileName'))">
{{ $t('export') }}
</a-button>
<!-- 带文件导出-->
<a-button icon="upload"
type="primary"
ghost
v-has="'domesticStandard:exportFile'"
@click="handleFileExport($t('standardRegulationLibrary.domesticStandard.exportFileName'))">
{{ $t('exportWithFile') }}
</a-button>
<!-- 模板下载-->
<a-button type="primary"
icon="download"
ghost
v-has="'domesticStandard:downTemplate'"
@click="downTemplate($t('standardRegulationLibrary.domesticStandard.templateName'))">
{{ $t('templateDownload') }}
</a-button>
<!-- 批量删除-->
<a-button type="primary" icon="delete" ghost @click="batchDel" v-has="'domesticStandard:batchDel'">{{
$t('batchDelete')
}}
</a-button>
<!-- 配置标准-->
<a-button type="primary" icon="setting" ghost @click="handleConfigStandard" v-has="'domesticStandard:configStandard'">
{{ $t('standardRegulationLibrary.configStandard') }}
</a-button>
<!-- 移出标准-->
<a-button type="primary"
icon="minus-circle"
ghost
@click="handleRemoveStandard"
v-has="'domesticStandard:removeStandard'">
{{ $t('standardRegulationLibrary.removeStandard') }}
</a-button>
</div>
<div>
<j-table
v-if="columns && columns.length > 0"
ref="tableRef"
:columns="columns"
:dataSource="dataSource"
:can-drag="true"
rowKey="id"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:pagination="ipagination"
:scroll="{x: '100%', y: yScrollHeight}"
:loading="loading"
@change="tableOnChange">
<!-- 标准编号-->
<template v-slot:standard_number="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="filePreview(record)">{{
text
}}
</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<!-- 标准名称-->
<template v-slot:standard_name="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="filePreview(record)">{{
text
}}
</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<template v-slot:operation="{text, record}">
<template v-if="operationList.length > operateMaxNum + 1">
<!-- 收藏-->
<a @click="operationClick(operationList[0],record)"
v-if="operationList[0].text === $t('standardRegulationLibrary.domesticStandard.cancelCollection')">
<i class="iconfont icon-star1" v-show="record.collectionFlag" />
<i class="iconfont icon-star" v-show="!record.collectionFlag" />
</a>
<a v-else @click="operationClick(operationList[0],record)">
<div class="operate-btn">
<!-- 查看图标-->
<i class="iconfont icon-link operate-btn-icon" v-if="operationList[0].text === $t('viewDetail')" />
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operationList[0].text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operationList[0].text === $t('delete')" />
{{ operationList[0].text }}
</div>
</a>
<a-divider type="vertical" />
<a-dropdown placement="bottomCenter">
<a-icon type="more" class="operate-icon-btn operate-icon-more" />
<a-menu slot="overlay">
<a-menu-item v-for="(operation, index) in operationList.slice(operateMaxNum)" :key="index">
<a @click="operationClick(operation,record)">
<div class="operate-btn">
<!-- 查看图标-->
<i class="iconfont icon-link operate-btn-icon" v-if="operation.text === $t('viewDetail')" />
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operation.text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operation.text === $t('delete')" />
{{ operation.text }}
</div>
</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template v-else-if="operationList.length > 0">
<template v-for="(operation, index) in operationList">
<!-- 收藏-->
<a :key="index" @click="operationClick(operationList[0],record)"
v-if="operation.text === $t('standardRegulationLibrary.domesticStandard.cancelCollection')">
<i class="iconfont icon-star1" v-show="record.collectionFlag" />
<i class="iconfont icon-star" v-show="!record.collectionFlag" />
</a>
<a v-else @click="operationClick(operation,record)" style="display: inline-block">
<div class="operate-btn">
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operation.text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operation.text === $t('delete')" />
{{ operation.text }}
</div>
</a>
<a-divider type="vertical" v-if="index !== operationList.length - 1" />
</template>
</template>
</template>
</j-table>
</div>
</div>
<!-- 新增编辑-->
<domestic-standard-modal ref="modalForm" @ok="modalFormOk" />
<!-- 树新增编辑-->
<domestic-system-tree-modal ref="treeModal" @ok="modalFormOk" />
<!-- 配置标准-->
<selection-domestic-standard-drawer ref="standardSelectionModal"
:node-code="selectedTreeNodeCodes[0]"
@change="continueConfigStandard" />
</a-card>
</template>
<script>
import Vue from 'vue'
import '@assets/less/common.less'
import { ConfigurableTableMixin } from '@/mixins/ConfigurableTableMixin'
import Search from '../../../components/customField/Search.vue'
import JTable from '../../../components/jero/JTable.vue'
import DomesticStandardModal from './modules/DomesticStandardModal.vue'
import {
configDomesticStandard,
deleteDomesticSystemTree,
getDomesticStandardDetail,
getDomesticStandardFormModal,
getDomesticStandardSearchForm,
getDomesticStandardTableHeader,
getDomesticStandardTree,
removeDomesticStandard,
collectionDomesticStandard,
cancelCollectionDomesticStandard
} from '../../../api/standardRegulationLibraryApi'
import {
OperationType,
StandardSource,
StandardStatus,
StandardSystemTreeNodeType,
YesOrNoEnum
} from '../../../enums/commonEnums'
import DomesticSystemTreeModal from './modules/DomesticSystemTreeModal.vue'
import SelectionDomesticStandardDrawer from './modules/SelectionDomesticStandardDrawer.vue'
import { postDownFile } from '@api/manage'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { previewPdf } from '@/utils/previewPdf'
import { kkFilePreview } from '@/utils/kkFilePreview'
import { getFileInfo } from '@api/api'
import { mapGetters } from 'vuex'
export default {
name: 'DomesticStandardList',
components: {
Search,
JTable,
DomesticStandardModal,
DomesticSystemTreeModal,
SelectionDomesticStandardDrawer
},
mixins: [ConfigurableTableMixin],
data () {
return {
StandardSystemTreeNodeType,
treeInput: null, // 树查询绑定值
treeData: [],
mouseInNodeKey: null, // 鼠标悬浮的节点key值
showAction: true,
operationList: [
// 收藏
{
text: this.$t('standardRegulationLibrary.domesticStandard.cancelCollection'),
clickEvent: 'handleCollection',
has: 'domesticStandard:collection'
},
// 查看
{
text: this.$t('viewDetail'),
clickEvent: 'toDetailPage',
has: 'domesticStandard:view'
},
// 编辑
{
text: this.$t('edit'),
clickEvent: 'handleEdit',
has: 'domesticStandard:edit'
},
// 删除
{
text: this.$t('delete'),
clickEvent: 'handleDelete',
has: 'domesticStandard:delete'
}
],
getTableHeaderFunc: getDomesticStandardTableHeader,
getQueryConditionFunc: getDomesticStandardSearchForm,
url: {
list: '/laws/standard/domestic/getCommonPage',
delete: '/laws/standard/domestic/deleteByIdsAndModule',
deleteBatch: '/laws/standard/domestic/deleteByIdsAndModule',
downTemplateUrl: '/laws/standard/domestic/templateDownload', // 下载模板
exportXlsUrl: '/laws/standard/domestic/exportData', // 导出
exportZipUrl: '/laws/standard/domestic/exportDataWithFile', // 带文件导出
importExcelUrl: '/laws/standard/domestic/importExcelWithData' // 导入
},
yesValue: YesOrNoEnum.YES.value,
noValue: YesOrNoEnum.NO.value,
selectedTreeKeys: [], // 选中的树节点key
selectedTreeNodeCodes: [], // 选中树节点的code
tableSlotField: ['standard_name', 'standard_number'], // 表格中需要插槽的字段
treeLoading: false,
isCollection: false,
expandedKeys: [], // 展开的节点
needFilterTableBtn: true,
defaultSearchParams: {
standard_state: `${StandardStatus.CURRENTLY_EFFECTIVE.value},${StandardStatus.BE_IMPLEMENTED_SOON.value},${StandardStatus.RELEASE.value}`
}
}
},
computed: {
...mapGetters(['userInfo']),
importExcelUrl () {
return `${window._CONFIG.domianURL}/${this.url.importExcelUrl}`
},
// 当前用户是否管理员
isAdmin () {
const adminRoleList = window._CONFIG.adminRoleCode.split(',')
const userRoleList = this.userInfo.roleCode.split(',')
return userRoleList.some(tt => adminRoleList.includes(tt))
}
},
created () {
this.initTreeData()
},
methods: {
/**
* 获取树数据
*/
initTreeData () {
this.treeLoading = true
const params = {
nodeName: this.treeInput
}
if (!params.nodeName) {
delete params.nodeName
}
getDomesticStandardTree(params).then(res => {
this.treeData = []
this.selectedTreeKeys = []
this.selectedTreeNodeCodes = []
this.filters.nodeCode = null
if (res.success) {
this.treeData = res.result || []
// 根节点默认展开
this.expandedKeys = [this.treeData[0].key]
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.treeLoading = false
})
},
/**
* 树节点查询
*/
handleTreeSearch () {
this.initTreeData()
},
/**
* 树节点鼠标移入
* @param key
*/
handleTreeMouseover (key) {
this.mouseInNodeKey = key
},
/**
* 树节点鼠标移出
* @param key
*/
handleTreeMouseout (key) {
if (this.mouseInNodeKey === key) {
this.mouseInNodeKey = null
}
},
/**
* 收藏/取消收藏
* @param record
*/
handleCollection ({ collectionFlag, id: standardId, standard_number: standardNumber }) {
if (this.isCollection) {
return
}
this.isCollection = true
let params
let submitFunc
// 取消收藏
if (collectionFlag) {
params = { id: standardId, standardNumber }
submitFunc = cancelCollectionDomesticStandard
} else {
params = { standardId, standardNumber }
submitFunc = collectionDomesticStandard
}
// 收藏
submitFunc(params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.isCollection = false
})
},
modalFormOk () {
this.selectedTreeKeys = []
this.filters.nodeCode = null
this.initTreeData()
// 新增/修改 成功时,重载列表
this.loadData()
// 清空列表选中
this.onClearSelected()
},
/**
* 新增树节点
* @param dataRef
*/
handleAddTreeNode ({ dataRef }) {
this.$refs.treeModal.add({ parentId: dataRef.id, parentCode: dataRef.nodeCode })
},
/**
* 编辑树节点
* @param dataRef
*/
handleEditTreeNode ({ dataRef }) {
this.$refs.treeModal.edit(dataRef)
},
/**
* 删除树节点
* @param dataRef
*/
handleDelTreeNode ({ dataRef }) {
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
deleteDomesticSystemTree({ id: dataRef.id }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.modalFormOk()
} else {
this.$message.warning(res.message)
}
})
}
})
},
/**
* 选中树节点
* @param dataRef
*/
handleSelectTreeNode ({ dataRef }) {
this.selectedTreeKeys = [dataRef.key]
this.selectedTreeNodeCodes = [dataRef.nodeCode]
this.filters.nodeCode = dataRef.nodeCode
this.loadData(1)
},
/**
* 配置标准
*/
handleConfigStandard () {
if (!this.selectedTreeNodeCodes || this.selectedTreeNodeCodes.length === 0 ||
this.selectedTreeNodeCodes.includes('MyCollection') || this.selectedTreeNodeCodes.includes('A02')) {
this.$message.warn(this.$t('standardRegulationLibrary.configStandardNoTreeNode'))
return
}
this.$refs.standardSelectionModal.open()
},
/**
* 配置标准-提交
* @param dbFieldName
* @param standardIds
*/
continueConfigStandard (dbFieldName, standardIds) {
this.loading = true
const params = {
nodeCode: this.selectedTreeNodeCodes[0],
ids: standardIds
}
configDomesticStandard(params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
/**
* 移出标准
*/
handleRemoveStandard () {
// 没选择左侧树节点,需要提示“请先选择二级及以下体系”
if (!this.selectedTreeNodeCodes || this.selectedTreeNodeCodes.length === 0 || this.selectedTreeNodeCodes.includes('A02')) {
this.$message.warn(this.$t('standardRegulationLibrary.configStandardNoTreeNode'))
return
}
// 左侧节点选的是我的收藏,不可移出标准
if (this.selectedTreeNodeCodes[0] === 'MyCollection') {
this.$message.warn(this.$t('enterpriseStandardLibrary.standard.myCollectNotRemove'))
return
}
// 没有选择列表数据,需要提示“选中至少一条列表数据”
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('standardRegulationLibrary.selectLeastOneTableData'))
return
}
this.loading = true
const params = {
nodeCode: this.selectedTreeNodeCodes[0],
ids: this.selectedRowKeys.join(',')
}
removeDomesticStandard(params).then(res => {
if (res.success) {
this.$message.success(res.message)
// 判断当前删除的数据是否是最后一页的最后一条数据,如果是的话页码减一
if (this.ipagination.current > 1 && ((this.ipagination.current - 1) * this.ipagination.pageSize) + 1 === this.ipagination.total) {
this.ipagination.current -= 1
}
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
/**
* 跳转详情页
* @param id
* @param standardNumber
*/
toDetailPage ({ id }) {
this.$openPageNewSheet({
path: '/standardRegulationLibrary/DomesticStandardDetail',
query: {
id
}
})
},
/**
* 按顺序打开最新的pdf或word
*/
async filePreview (record) {
console.log('filePreview', record)
// 获取并处理过程稿件数据
let res = await getDomesticStandardFormModal({ type: 1 })
if (!res.success) {
this.$message.warn(res.message)
console.log('getDomesticStandardFormModal error:', res)
return
}
console.log('res.result', res.result)
const data = res.result || {}
const form = data
const partList = Object.keys(data)
let part
const partZh = '过程稿件'
const partEn = 'Process Manuscript'
if (partList.includes(partEn))part = partEn
if (partList.includes(partZh))part = partZh
console.log('part', part)
const processManuscript = form[part]
console.log('过程稿件', processManuscript)
// 获取并处理详情数据
res = await getDomesticStandardDetail({ id: record.id, type: 1 })
if (!res.success) {
this.$message.warn(res.message)
console.log('getDomesticStandardDetail error:', res)
return
}
const detailData = Object.assign({}, res.result || {})
console.log('detailData', detailData)
// 选择合适的文件
let file = null
const pdfFileList = []
const docFileList = []
let newestFileList = []
// 按照过程稿件顺序寻找文件
for (const formItem of processManuscript) {
const keyId = formItem.dbFieldName
const keyName = formItem.dbFieldName + '_dictText'
if (!detailData[keyId]) continue
const idArray = detailData[keyId].split(',')
const nameArray = detailData[keyName].split(',')
// 每个过程中可能有多个文件
for (let i = 0; i < idArray.length; i++) {
const id = idArray[i]
const name = nameArray[i]
var suffix = name.substring(name.lastIndexOf('.') + 1).toLowerCase()
if (suffix === 'pdf') {
pdfFileList.push({ id, name, suffix })
}
if (suffix === 'docx') {
docFileList.push({ id, name, suffix })
}
}
// 一旦一个过程中找到pdf或者doc,就可以退出
if (pdfFileList.length > 0 || docFileList.length > 0) {
break
}
}
newestFileList = pdfFileList // 默认从pdf里选最新的文件
if (pdfFileList.length === 0)newestFileList = docFileList // 如果没有pdf文件,就从doc文件里选
file = await this.selectNewestFile(newestFileList)
if (file === null) { // 没有找到文件就退出
console.log('没有找到符合要求的文件!')
this.$message.error('该标准暂无预览文件,请联系标准管理员。')
return
}
console.log('seletedFile', file)
// 预览选择的文件
const fileFullUrl = `${window._CONFIG.domianWebSocketURL}/sys/common/view/${file.id}?at=${Vue.ls.get(ACCESS_TOKEN)}&fullfilename=${file.name}`
console.log(fileFullUrl)
if (file.suffix === 'pdf') { // pdf预览
const url = previewPdf(file.id)
window.open(url)
return
}
kkFilePreview(fileFullUrl)// 其余可预览文件仍使用KKFile进行预览
},
/**
* 从文件列表里选择最新文件
* @param fileList
*/
async selectNewestFile (fileList) {
if (!fileList || fileList.length === 0) return null
if (fileList.length === 1) return fileList[0]
const newFileList = []
// 获取时间信息
for (const file of fileList) {
const res = await getFileInfo(file)
newFileList.push({ ...file, ...res.result })
}
// 排序取出最新
newFileList.sort((a, b) => b.id - a.id) // 日期只精确到天,用id更能区分
console.log('newFileList', newFileList)
return newFileList[0]
},
/**
* 重置查询
*/
searchReset (params) {
this.searchParams = Object.assign({}, params)
this.selectedRowKeys = []
this.selectedTreeKeys = []
delete this.filters.nodeCode
this.getTableHeader()
this.loadData()
},
// 导出改成用post
handleExportXls (fileName) {
if (!fileName || typeof fileName !== 'string') {
fileName = '导出文件'
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
console.log('导出参数', param)
// 加一个大的提示
const modalLoading = this.$info({
title: '提示',
content: <span>正在导出请稍候 <a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
postDownFile(this.url.exportXlsUrl, param).then((data) => {
if (!data || data.size === 0) {
this.$message.warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName + '.xls')
} else {
const url = window.URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + '.xls')
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
// 带文件导出
handleFileExport (fileName) {
if (!fileName || typeof fileName !== 'string') {
fileName = '导出文件'
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
param.module = StandardSource.DOMESTIC.value
console.log('导出参数', param)
// 加一个大的提示
const modalLoading = this.$info({
title: '提示',
content: <span>正在导出请稍候 <a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
postDownFile(this.url.exportZipUrl, param).then((data) => {
if (!data) {
this.$message.warning('文件下载失败')
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName + '.zip')
} else {
const url = window.URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
// }
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
/**
* 新增-非管理员用户跳转流程发起页面,不能修改操作类型
*/
handleAdd () {
if (!this.isAdmin) {
this.$router.push({
path: '/workCenter/StandardEntryOrChangeProcess',
query: {
source: StandardSource.DOMESTIC.value, // 国内标准
operateType: OperationType.ENTRY.value // 入库
}
})
return
}
this.$refs.modalForm.add()
this.$refs.modalForm.title = this.$t('newlyAdded')
this.$refs.modalForm.disableSubmit = false
},
handleEdit (record) {
if (!this.isAdmin) {
this.$router.push({
path: '/workCenter/StandardEntryOrChangeProcess',
query: {
source: StandardSource.DOMESTIC.value, // 国内标准
operateType: OperationType.CHANGE.value, // 变更
standardId: record.id // 标准id
}
})
return
}
this.$refs.modalForm.edit(record)
this.$refs.modalForm.title = this.$t('edit')
this.$refs.modalForm.disableSubmit = false
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
/deep/ .ant-tree li span.ant-tree-switcher.ant-tree-switcher-noop {
color: #1D2129;
}
.parent-node-icon {
color: #1D2129;
font-size: 16px;
margin-right: 10px;
}
</style>
@@ -0,0 +1,144 @@
<template>
<a-drawer
:title="title"
:width="width"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
:maskClosable="false"
destroyOnClose
class="custom-drawer-style"
>
<div class="custom-drawer-style-scroll">
<a-spin :spinning="confirmLoading" style="width: 100%;height:100%">
<add-form ref="addForm"
:flag="StandardSource.DOMESTIC.value"
:get-form-func="getFormFunc"
:get-document-info-func="getDocumentInfoFunc"
:special-placeholder="specialPlaceholder"
:default-value="defaultValue"
:disabled-field-list="disabledField"
:open-selected-all-field-list="openSelectedAllFieldList"
:exclude-standard-fields="excludeStandardFields"
domestic-special-check
:flag-by-field="{associated_foreign_standards: StandardSource.OVERSEAS.value}"
@submitFormData="submitFormData" />
</a-spin>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel" style="margin-bottom: 0;" :loading="confirmLoading">{{ $t('close') }}</a-button>
<a-button @click="handleOk" type="primary" style="margin-bottom: 0;" :loading="confirmLoading">
{{ $t('preservation') }}
</a-button>
</div>
</a-drawer>
</template>
<script>
import AddForm from '../../../../components/customField/AddForm.vue'
import {
getDomesticStandardDocumentInfo,
getDomesticStandardFormModal,
addDomesticStandard,
editDomesticStandard
} from '../../../../api/standardRegulationLibraryApi'
import { StandardSource } from '../../../../enums/commonEnums.js'
export default {
name: 'DomesticStandardModal',
components: { AddForm },
data () {
return {
StandardSource,
visible: false,
title: '',
width: 800,
// 存储表单的数据
form: {},
confirmLoading: false,
getFormFunc: getDomesticStandardFormModal,
getDocumentInfoFunc: getDomesticStandardDocumentInfo,
// 特殊的placeholder
specialPlaceholder: {
standard_number_temp: `${this.$t('standardRegulationLibrary.inputExample')}7258`
},
defaultValue: {
year_number: new Date().getFullYear() + ''
},
// 数据字典多选,需要全选功能的字段
openSelectedAllFieldList: [
'applicable_vehicle', // 适用车型
'dynamic_type' // 动力类型
],
isEdit: null // 是否编辑
}
},
computed: {
// 不可编辑的字段
disabledField () {
if (this.isEdit) {
// 标准编号,被代替标准号,被引用标准号,标准类别,年代号
return ['standard_number_temp', 'replaced_by_standard_number', 'referenced_standard', 'standard_class', 'year_number']
}
return ['replaced_by_standard_number', 'referenced_standard']
},
excludeStandardFields () {
if (this.isEdit) {
return ['substitute_standard_number', 'reference_standard']
}
return []
}
},
methods: {
add () {
this.visible = true
this.isEdit = false
this.$nextTick(() => {
this.$refs.addForm.add()
})
},
edit (record) {
this.visible = true
this.isEdit = true
this.$nextTick(() => {
this.$refs.addForm.edit(record)
})
},
handleOk () {
this.$refs.addForm.submit()
},
// 表单提交的回调,获取表单数据
submitFormData (formInline) {
this.confirmLoading = true
let submitFunc
if (formInline.id) {
submitFunc = editDomesticStandard
} else {
submitFunc = addDomesticStandard
}
submitFunc(formInline).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,103 @@
<template>
<j-modal
:title="title"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('standardRegulationLibrary.nodeName')">
<a-input :placeholder="$t('pleaseEnter') + $t('standardRegulationLibrary.nodeName')"
:maxLength="50"
v-decorator="['nodeName', validatorRules.nodeName]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import { addDomesticSystemTree, editDomesticSystemTree } from '../../../../api/standardRegulationLibraryApi'
export default {
name: 'DomesticSystemTreeModal',
data () {
return {
title: this.$t('operation'),
width: 800,
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 节点名称
nodeName: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('standardRegulationLibrary.nodeName') }],
validateTrigger: 'blur'
}
}
}
},
methods: {
add (parentInfo) {
this.edit(parentInfo)
},
edit (record) {
this.form.resetFields()
this.model = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
close () {
this.visible = false
},
handleOk () {
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
const formData = Object.assign(this.model, values)
formData.nodeOrder = '0'
let submitFunc
if (this.model.id) {
submitFunc = editDomesticSystemTree
} else {
submitFunc = addDomesticSystemTree
}
submitFunc(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel () {
this.close()
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,238 @@
<template>
<a-drawer
:title="$t('standardSelect.standardSelection')"
:maskClosable="false"
:width="1000"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
class="custom-drawer-style">
<div class="custom-drawer-style-scroll">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :sm="8">
<a-form-item :label="$t('standardSelect.standardNumOrName')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter')+$t('standardSelect.standardNumOrName')"
v-model="queryParam.standardNumberOrName"></a-input>
</a-form-item>
</a-col>
<div style="float: right;overflow: hidden;margin-right: 41px;margin-bottom: 20px"
class="table-page-search-submitButtons">
<a-button class="box-button" style="margin-left: 8px" @click="searchReset">{{ $t('reset') }}</a-button>
<a-button class="box-button" style="margin-left: 8px" type="primary" @click="searchQuery">{{
$t('query')
}}
</a-button>
</div>
</a-row>
</a-form>
</div>
<a-table
:columns="columns"
rowKey="serial_number"
:scroll="{x: 900}"
:data-source="dataList"
:pagination="ipagination"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:loading="loading"
@change="handleTableChange">
<!-- 标准编号标准名称跳转详情-->
<template v-slot:detail="text, record">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="toDetailPage(record)">{{ text }}</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<template slot="text" slot-scope="text">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text">{{ text || text === 0 ? text : global.emptyLine }}</div>
</a-tooltip>
</template>
</a-table>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button @click="handleSubmit" type="primary" :loading="confirmLoading">{{ $t('submit') }}</a-button>
</div>
</a-drawer>
</template>
<script>
import { getDomesticStandardNoSystem } from '../../../../api/standardRegulationLibraryApi.js'
import { StandardSource } from '../../../../enums/commonEnums.js'
export default {
name: 'SelectionDomesticStandardDrawer',
props: {
// 选中节点code
nodeCode: {
type: String,
required: false,
default: null
},
query: {
type: Object,
required: false,
default: () => {
return {}
}
}
},
data () {
return {
visible: false,
confirmLoading: false,
labelCol: {
sm: 8
},
wrapperCol: {
sm: 14
},
selectedRowKeys: [],
selectedRowList: [],
loading: false,
queryParam: {},
/* 分页参数 */
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '30', '50', '100', '150', '200'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' ' + this.$t('total') + ' ' + total + ' ' + this.$t('strip')
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
columns: [
// 标准号
{
title: this.$t('standardSelect.standardNumber'),
dataIndex: 'standardNumber',
align: 'center',
width: 150,
scopedSlots: { customRender: 'detail' }
},
// 标准名称
{
title: this.$t('standardSelect.standardName'),
dataIndex: 'standardName',
align: 'center',
width: 150,
scopedSlots: { customRender: 'detail' }
},
// 发布日期
{
title: this.$t('standardSelect.releaseDate'),
dataIndex: 'releaseDate',
align: 'center',
width: 120,
scopedSlots: { customRender: 'text' }
},
// 标准状态
{
title: this.$t('projectLibrary.vehicleItemLibrary.standardState'),
dataIndex: 'standardState_dictText',
align: 'center',
width: 120,
scopedSlots: { customRender: 'text' }
}
],
dataList: [],
url: {
searchList: 'document/bussDocumentLibraryEO/queryCondition' // 搜索字段
}
}
},
methods: {
open () {
this.visible = true
this.queryParam = {}
this.replacePage()
},
// 获取表格数据
replacePage () {
const query = {
...this.queryParam,
pageNo: this.ipagination.current,
pageSize: this.ipagination.pageSize,
nodeCode: this.nodeCode,
source: StandardSource.DOMESTIC.value
}
this.selectedRowKeys = []
this.loading = true
getDomesticStandardNoSystem(query).then((res) => {
if (res.success) {
this.dataList = res.result.records
this.ipagination.total = res.result.total
this.selectedRowKeys = this.standard[this.query.db_field_name] ? this.standard[this.query.db_field_name].split(',') : []
} else {
this.dataList = []
}
}).finally(() => {
this.loading = false
})
},
searchQuery () {
this.replacePage()
},
searchReset () {
this.queryParam = {}
this.replacePage()
},
// 表格选择改变
onSelectChange (value, row) {
this.selectedRowKeys = value
this.selectedRowList = row
},
handleCancel () {
this.visible = false
},
handleSubmit () {
const serialNumber = []
const replaceStandardId = []
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
// let content = JSON.parse(JSON.stringify(this.selectedRowList))
this.selectedRowList.forEach(res => {
serialNumber.push(res.serial_number)
replaceStandardId.push(res.id)
})
this.$emit('input', serialNumber.join(','))
this.$emit('change', this.query.dbFieldName, replaceStandardId.join(','))
// this.$emit('changecontent', this.content)
this.visible = false
} else {
this.$message.warning(this.$t('selectLeastOne'))
}
},
/**
* 跳转详情页
* @param id
*/
toDetailPage ({ id }) {
this.$openPageNewSheet({
path: '/standardRegulationLibrary/DomesticStandardDetail',
query: {
id
}
})
},
handleTableChange (pagination) {
this.ipagination = pagination
this.replacePage()
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,132 @@
<template>
<internal-detail-page :title="$t('standardRegulationLibrary.dynamicMessage.dynamicDetails')" :loading="loading" :content-padding="0">
<div class="page-title-img">
<img src="../../../assets/image/dynamicMessageDetailBg.png" alt="" />
</div>
<div class="detail-content">
<div class="detail-title">
{{ $t('standardRegulationLibrary.dynamicMessage.dynamicDetails') }}{{ detailData.dynamicHeading }}
</div>
<div class="decoration">
<!--浏览量-->
<div class="page-view decoration-item">
<a-icon type="eye" />
{{ detailData.readCount }}
</div>
<!--编辑人-->
<div class="writer decoration-item">
<label>{{ $t('docTool.split.editor') }}</label>
<span>{{ detailData.writer_dictText }}</span>
</div>
<!--发布时间-->
<div class="writer decoration-item">
<label>{{ $t('standardRegulationLibrary.dynamicMessage.releaseTime') }}</label>
<span>{{ detailData.releaseTime }}</span>
</div>
</div>
<div class="container">
<div class="container-title">{{ $t('standardRegulationLibrary.dynamicMessage.dynamicDetails') }}</div>
<div v-html="detailData.dynamicDetails"></div>
<file-echo :file-ids="detailData.dataText" :operate-fixed-right="false" class="file-box" />
</div>
</div>
</internal-detail-page>
</template>
<script>
import InternalDetailPage from '../../../components/InternalDetailPage.vue'
import { getDynamicMessageById } from '../../../api/standardRegulationLibraryApi.js'
import FileEcho from '../../../components/FileEcho.vue'
export default {
name: 'DynamicMessageDetail',
components: { InternalDetailPage, FileEcho },
data () {
return {
loading: false,
detailData: {},
fileList: []
}
},
created () {
this.initData()
},
methods: {
initData () {
getDynamicMessageById({ id: this.$route.query.id, type: 'query' }).then(res => {
if (res.success) {
this.detailData = Object.assign({}, res.result || {})
} else {
this.$message.warn(res.message)
}
})
}
}
}
</script>
<style scoped lang="less">
.page-title-img {
width: 100%;
img {
width: 100%;
}
}
.detail-content {
margin: 0 230px;
}
.detail-title {
margin-top: 30px;
font-size: 22px;
font-family: PingFang SC-Semibold, PingFang SC, sans-serif;
font-weight: 600;
color: #1D2129;
text-align: center;
}
.decoration {
padding: 8px 0;
border-bottom: 1px solid #E5E6EB;
text-align: right;
&-item {
display: inline-block;
margin-left: 20px;
}
}
.writer {
font-size: 14px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
font-weight: 400;
label {
color: #4E5969;
margin-right: 8px;
}
span {
color: #86909C;
}
}
.container {
margin-top: 24px;
&-title {
font-size: 16px;
font-family: PingFang SC-Medium, PingFang SC, sans-serif;
font-weight: 550;
color: #1D2129;
margin-bottom: 8px;
}
}
.file-box {
margin-top: 10px;
}
</style>
@@ -0,0 +1,364 @@
<template>
<internal-detail-page :title="$route.query.title" :content-padding="0" :loading="loading">
<a-form :form="form">
<a-row>
<!--动态标题-->
<a-col :span="12">
<a-form-item :label="$t('standardRegulationLibrary.dynamicMessage.dynamicHeading')"
:labelCol="labelCol"
:wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('standardRegulationLibrary.dynamicMessage.dynamicHeading')"
:maxLength="200"
v-decorator="['dynamicHeading', validatorRules.dynamicHeading]" />
</a-form-item>
</a-col>
<!--动态分类-->
<a-col :span="12">
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('standardRegulationLibrary.dynamicMessage.dynamicCataloging')">
<j-dict-select-tag v-decorator="['dynamicClassification', validatorRules.dynamicClassification]"
dict-code="dynamic_news_type"
:placeholder="$t('pleaseSelect') + $t('standardRegulationLibrary.dynamicMessage.dynamicCataloging')"
@change="handleCatalogingChange" />
</a-form-item>
</a-col>
</a-row>
<!--推送范围-->
<a-form-item :labelCol="lineLabelCol"
:wrapperCol="lineWrapperCol"
:label="$t('standardRegulationLibrary.dynamicMessage.pushRange')">
<user-selection v-decorator="['pushRange', validatorRules.pushRange]"
type="checkbox"
:name-str="modal.pushRange_dictText"
:placeholder="$t('pleaseSelect') + $t('standardRegulationLibrary.dynamicMessage.pushRange')" />
</a-form-item>
<!--动态详情-->
<a-form-item v-if="needWriteDynamicDetails"
:labelCol="lineLabelCol"
:wrapperCol="lineWrapperCol"
:label="$t('standardRegulationLibrary.dynamicMessage.dynamicDetails')">
<u-editor :content="ueContent" :config="config" ref="uEditor" @editor-onChange="uEditorChange" />
</a-form-item>
<!--资料文本-->
<a-form-item :labelCol="lineLabelCol"
:wrapperCol="lineWrapperCol"
:label="$t('standardRegulationLibrary.dynamicMessage.dataText')">
<j-upload v-decorator="['dataText', validatorRules.dataText]"
return-id
:number="fileNum"
:file-type="fileType"
:multiple="fileNum !== 1" />
</a-form-item>
</a-form>
<div class="bottom-operate-box">
<!--取消-->
<a-button type="primary" ghost :loading="loading" @click="handleCancel">{{ $t('cancel') }}</a-button>
<!--保存-->
<a-button type="primary" :loading="loading" @click="handleSave" v-has="'dynamicMessage:save'">{{
$t('preservation')
}}
</a-button>
<!--发布-->
<a-button type="primary" :loading="loading" @click="handlePublish" v-has="'dynamicMessage:release'">{{
$t('release')
}}
</a-button>
</div>
</internal-detail-page>
</template>
<script>
import InternalDetailPage from '../../../components/InternalDetailPage.vue'
import UserSelection from '../../../components/selection/UserSelection.vue'
import UEditor from '../../../components/uEditor/UEditor.vue'
import { saveDynamicMessage, getDynamicMessageById, releaseDynamicMessage } from '../../../api/standardRegulationLibraryApi.js'
import { DynamicCataloging } from '../../../enums/commonEnums.js'
// 本系统限制可以上传的文件格式
const CAN_UPLOAD_FILE_TYPE = 'pdf,docx,doc,xlsx,xls,ppt,pptx,rar,.zip,jpg,jpeg,png,avi,wmv,mov,rm,mp4,cad'
export default {
name: 'DynamicMessageFormPage',
components: { UEditor, InternalDetailPage, UserSelection },
data () {
return {
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 }
},
lineLabelCol: {
xs: { span: 24 },
sm: { span: 2 }
},
lineWrapperCol: {
xs: { span: 24 },
sm: { span: 21 }
},
ueContent: '',
// UE编辑器配置
config: {
// 可以在此处定义工具栏的内容
toolbars: [
[
'undo', // 撤销
'redo', // 重做
'bold', // 加粗
'italic', // 斜体
'underline', // 下划线
'strikethrough', // 删除线
'subscript', // 下标
'superscript', // 上标
'fontborder', // 字符边框
'fontfamily', // 字体
'fontsize', // 字号
'forecolor', // 字体颜色
// 'backcolor', // 背景色
'paragraph', // 段落格式
'customstyle', // 自定义标题
'indent', // 首行缩进
'justifyleft', // 居左对齐
'fullscreen', // 全屏
'justifyright', // 居右对齐
'justifycenter', // 居中对齐
'justifyjustify', // 两端对齐
'lineheight', // 行间距,
'rowspacingtop', // 段前距
'rowspacingbottom', // 段后距
'directionalityltr', // 从左向右输入
'directionalityrtl', // 从右向左输入
'cleardoc', // 清空文档
'formatmatch', // 格式刷
'removeformat', // 清除格式
'source', // 源代码
'blockquote', // 引用
'pasteplain', // 纯文本粘贴模式
'selectall', // 全选
'horizontal', // 分隔线
'time', // 时间
'date', // 日期
'link', // 超链接
'unlink', // 取消链接
// 'background', // 背景
// 'simpleupload', // 单图上传
'imagenone', // 默认
'imageleft', // 左浮动
'imageright', // 右浮动
'imagecenter', // 居中
'touppercase', // 字母大写
'tolowercase', // 字母小写
'emotion', // 表情
'spechars', // 特殊字符
'searchreplace', // 查询替换
'insertunorderedlist', // 无序列表
'insertorderedlist', // 有序列表
'pagebreak', // 分页
'insertframe', // 插入Iframe
'charts', // 图表
'edittip ', // 编辑提示
'autotypeset', // 自动排版
'drafts', // 从草稿箱加载
'inserttable', // 插入表格
'deletetable', // 删除表格,
'insertparagraphbeforetable', // ”表格前插入行”
'insertrow', // 前插入行
'insertcol', // 前插入列
'mergeright', // 右合并单元格
'mergedown', // 下合并单元格
'deleterow', // 删除行
'deletecol', // 删除列
'splittorows', // 拆分成行
'splittocols', // 拆分成列
'splittocells', // 完全拆分单元格
'inserttitle', // 插入标题
'deletecaption', // 删除表格标题,
'mergecells', // 合并多个单元格
'edittable', // 表格属性
'edittd' // 单元格属性
]
],
autoHeightEnabled: false,
autoFloatEnabled: false,
initialContent: '', // 初始化编辑器的内容,也可以通过textarea/script给值,看官网例子
autoClearinitialContent: true, // 是否自动清除编辑器初始内容,注意:如果focus属性设置为true,这个也为真,那么编辑器一上来就会触发导致初始化的内容看不到了
initialFrameWidth: '100%',
elementPathEnabled: false,
initialFrameHeight: 300,
maximumWords: 4000,
BaseUrl: '',
UEDITOR_HOME_URL: '/ueditor/',
editTableIndex: 1
},
fileNum: 0, // 动态分类为周报或月报时,控制只能上传一个
fileType: CAN_UPLOAD_FILE_TYPE, // 动态分类为周报或月报时,控制只能上传pdf
validatorRules: {
// 动态标题
dynamicHeading: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('standardRegulationLibrary.dynamicMessage.dynamicHeading')
}],
validateTrigger: 'blur'
},
// 动态分类
dynamicClassification: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('standardRegulationLibrary.dynamicMessage.dynamicCataloging')
}],
validateTrigger: 'change'
},
// 推送范围
pushRange: {
rules: [{
required: false,
message: this.$t('pleaseSelect') + this.$t('standardRegulationLibrary.dynamicMessage.pushRange')
}],
validateTrigger: 'change'
},
// 资料文本
dataText: {
rules: [{
required: false,
message: this.$t('uploadFile.pleaseUpload') + this.$t('standardRegulationLibrary.dynamicMessage.dataText')
}],
validateTrigger: 'change'
}
},
loading: false,
modal: {},
needWritePushRange: true, // 是否需要填写推送范围
needWriteDynamicDetails: true // 是否需要填写动态详情
}
},
mounted () {
if (this.$route.query.id) {
this.initFormData()
}
},
methods: {
initFormData () {
this.loading = true
getDynamicMessageById({ id: this.$route.query.id, type: 'edit' }).then(res => {
if (res.success) {
this.modal = res.result || {}
this.$nextTick(() => {
if (this.modal.dynamicClassification === DynamicCataloging.WEEKLY_NEWSPAPER.value || this.modal.dynamicClassification === DynamicCataloging.MONTHLY_MAGAZINE.value) {
this.fileNum = 1
this.fileType = 'pdf'
this.needWritePushRange = false
this.needWriteDynamicDetails = false
} else {
this.fileNum = 0
this.fileType = CAN_UPLOAD_FILE_TYPE
this.needWritePushRange = true
}
this.form.setFieldsValue(this.modal)
this.ueContent = this.modal.dynamicDetails
this.$refs.uEditor.setContent(this.ueContent)
})
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
// 获取表格内容
uEditorChange (val) {
console.log('--------------uEditorChange------------', val)
this.ueContent = val
},
handleSave () {
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = Object.assign(this.modal, values)
formData.dynamicDetails = this.ueContent
this.loading = true
saveDynamicMessage(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$router.go(-1)
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
}
})
},
handleCatalogingChange (value) {
if (value === DynamicCataloging.WEEKLY_NEWSPAPER.value || value === DynamicCataloging.MONTHLY_MAGAZINE.value) {
this.fileNum = 1
this.fileType = 'pdf'
this.needWritePushRange = false
this.needWriteDynamicDetails = false
this.form.setFieldsValue({ dataText: undefined })
} else {
this.fileNum = 0
this.fileType = CAN_UPLOAD_FILE_TYPE
this.needWritePushRange = true
this.needWriteDynamicDetails = true
}
},
handlePublish () {
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = Object.assign(this.modal, values)
formData.dynamicDetails = this.ueContent
this.loading = true
releaseDynamicMessage(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$router.go(-1)
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
}
})
},
handleCancel () {
this.$router.go(-1)
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
/deep/ .edui-default .edui-editor {
width: 100% !important;
}
/deep/ .edui-default .edui-toolbar {
line-height: 20px;
}
.bottom-operate-box {
height: 52px;
padding: 10px 32px;
text-align: right;
.ant-btn {
margin-left: 15px;
}
}
.ant-form {
height: calc(100% - 52px);
box-sizing: border-box;
overflow: auto;
padding: 32px 0;
}
</style>
@@ -0,0 +1,185 @@
<template>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<!--标题-->
<a-col :md="6" :sm="12">
<a-form-item :label="$t('title')">
<a-input :placeholder="$t('pleaseEnter') + $t('title')" v-model="queryParam.dynamicHeading" />
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary"
@click="searchQuery"
icon="search"
style="margin-left: 8px"
v-has="'dynamicMessage:search'">
{{ $t('query') }}
</a-button>
<a-button type="primary" @click="searchReset" icon="reload" ghost>{{ $t('reset') }}</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
<div class="table-operator">
<!--新增-->
<a-button icon="plus" type="primary" @click="handleAdd" v-has="'dynamicMessage:add'">{{ $t('newlyAdded') }}</a-button>
<!--批量删除-->
<a-button type="primary" icon="delete" ghost @click="batchDel" v-has="'dynamicMessage:deleteBatch'">{{ $t('batchDelete') }}
</a-button>
</div>
<div>
<j-table
:columns="columns"
:dataSource="dataSource"
:can-drag="true"
rowKey="id"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:pagination="ipagination"
:scroll="{x: 1000, y: yScrollHeight}"
:loading="loading"
:operation-list="operationList"
@change="handleTableChange"
@operationClick="operationClick">
<!-- 标准编号-->
<template v-slot:click="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="toDetailPage(record)">{{ text }}</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
</j-table>
</div>
</a-card>
</template>
<script>
import { JeroListMixin } from '../../../mixins/JeroListMixin.js'
import JTable from '../../../components/jero/JTable.vue'
import { mapGetters } from 'vuex'
export default {
name: 'DynamicMessageList',
components: { JTable },
mixins: [JeroListMixin],
computed: {
...mapGetters(['userInfo']),
// 是否管理员
isAdmin () {
const adminRoleList = window._CONFIG.adminRoleCode.split(',')
const userRoleList = this.userInfo.roleCode.split(',')
return userRoleList.some(tt => adminRoleList.includes(tt))
}
},
data () {
return {
operationList: [
// 编辑
{
text: this.$t('edit'),
clickEvent: 'handleEdit',
has: 'dynamicMessage:edit',
// 管理员可以编辑/删除所有,编辑人能修改/删除自己发布的,其他用户只能收藏/查看和分享
show: (record) => {
return this.isAdmin || record.writer === this.userInfo.id
}
},
// 删除
{
text: this.$t('delete'),
clickEvent: 'handleDelete',
has: 'dynamicMessage:delete',
// 管理员可以编辑/删除所有,编辑人能修改/删除自己发布的,其他用户只能收藏/查看和分享
show: (record) => {
return this.isAdmin || record.writer === this.userInfo.id
}
}
],
columns: [
// 动态标题
{
dataIndex: 'dynamicHeading',
title: this.$t('standardRegulationLibrary.dynamicMessage.dynamicHeading'),
width: 200,
scopedSlots: { customRender: 'click' }
},
// 动态分类
{
dataIndex: 'dynamicClassification_dictText',
title: this.$t('standardRegulationLibrary.dynamicMessage.dynamicCataloging'),
width: 150
},
// 编辑人
{
dataIndex: 'writer_dictText',
title: this.$t('docTool.split.editor'),
width: 150
},
// 发布状态
{
dataIndex: 'releaseStatus_dictText',
title: this.$t('standardRegulationLibrary.dynamicMessage.releaseStatus'),
width: 150
},
// 发布时间
{
dataIndex: 'releaseTime',
title: this.$t('standardRegulationLibrary.dynamicMessage.releaseTime'),
width: 150
},
// 操作
{
title: this.$t('operation'),
fixed: 'right',
width: 150,
scopedSlots: { customRender: 'action' }
}
],
url: {
list: '/laws/standard/lawsNewsFeed/page',
delete: '/laws/standard/lawsNewsFeed/delete',
deleteBatch: '/laws/standard/lawsNewsFeed/deleteBatch'
}
}
},
methods: {
handleAdd () {
this.$router.push({
path: '/standardRegulationLibrary/DynamicMessageFormPage',
query: {
title: this.$t('newlyAdded')
}
})
},
handleEdit ({ id }) {
this.$router.push({
path: '/standardRegulationLibrary/DynamicMessageFormPage',
query: {
title: this.$t('edit'),
id
}
})
},
toDetailPage ({ id }) {
this.$router.push({
path: '/standardRegulationLibrary/DynamicMessageDetail',
query: {
id
}
})
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
</style>
@@ -0,0 +1,826 @@
<template>
<a-card :bordered="false" class="page-left-right-layout">
<!-- 树部分-->
<div class="page-left-box">
<a-input-search v-model="treeInput" class="tree-search"
:placeholder="$t('standardRegulationLibrary.domesticStandard.treeSearchPlaceholder')"
@search="handleTreeSearch" />
<div class="page-tree-box page-tree-box-has-search">
<a-spin :spinning="treeLoading">
<a-tree :show-line="true"
:show-icon="true"
:tree-data="treeData"
:expanded-keys.sync="expandedKeys"
:selected-keys="selectedTreeKeys">
<template #title="record">
<div class="tree-operate-node"
@mouseenter="handleTreeMouseover(record.key)"
@mouseleave="handleTreeMouseout(record.key)"
@click="handleSelectTreeNode(record)">
<a-icon class="parent-node-icon"
type="folder"
v-if="record.dataRef.children && record.dataRef.children.length > 0" />
<a-tooltip>
<template #title>
{{ record.title }}
</template>
<span class="tree-node-custom-title">{{ record.title }}</span>
</a-tooltip>
<div class="tree-operate-node-btn-box" :class="{'tree-operate-node-btn-box-hide': record.key !== mouseInNodeKey}">
<!-- 新增-->
<a-button icon="plus"
class="tree-operate-node-btn"
@click.stop="handleAddTreeNode(record)"
v-if="record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value"
v-has="'overseasStandard:tree:add'"></a-button>
<!-- 编辑根节点不能编辑-->
<a-button class="tree-operate-node-btn"
@click.stop="handleEditTreeNode(record)"
v-has="'overseasStandard:tree:edit'"
v-if="record.nodeType !== StandardSystemTreeNodeType.ROOT_NODE.value && record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value">
<i class="iconfont icon-bianji" />
</a-button>
<!-- 删除根节点不能删除-->
<a-button class="tree-operate-node-btn"
v-has="'overseasStandard:tree:delete'"
v-if="record.nodeType !== StandardSystemTreeNodeType.ROOT_NODE.value && record.nodeType !== StandardSystemTreeNodeType.NOT_OPERATE_NODE.value"
@click.stop="handleDelTreeNode(record)">
<i class="iconfont icon-shanchu_" />
</a-button>
</div>
</div>
</template>
</a-tree>
</a-spin>
</div>
</div>
<!-- 表格部分-->
<div class="page-right-box">
<div class="table-page-search-wrapper">
<search ref="searchRef"
:url="url"
:get-query-condition-func="getQueryConditionFunc"
:default-search-params="defaultSearchParams"
search-has="overseasStandard:search"
@search="searchQuery"
@reset="searchReset" />
</div>
<div class="table-operator">
<!-- 新增-->
<a-button icon="plus" type="primary" @click="handleAdd" v-has="'overseasStandard:add'">{{ $t('newlyAdded') }}</a-button>
<!-- 导入-->
<a-upload name="file"
:showUploadList="false"
:multiple="false"
:headers="tokenHeader"
:action="importExcelUrl"
v-has="'overseasStandard:import'"
@change="handleImportExcel">
<a-button type="primary" icon="download" ghost>{{ $t('import') }}</a-button>
</a-upload>
<!-- 导出-->
<a-button icon="upload"
type="primary"
ghost
v-has="'overseasStandard:export'"
@click="handleExportXls($t('standardRegulationLibrary.overseasStandard.exportFileName'))">
{{ $t('export') }}
</a-button>
<!-- 带文件导出-->
<a-button icon="upload"
type="primary"
ghost
v-has="'overseasStandard:exportFile'"
@click="handleFileExport($t('standardRegulationLibrary.overseasStandard.exportFileName'))">
{{ $t('exportWithFile') }}
</a-button>
<!-- 模板下载-->
<a-button type="primary"
icon="download"
ghost
v-has="'overseasStandard:downTemplate'"
@click="downTemplate($t('standardRegulationLibrary.overseasStandard.templateName'))">
{{ $t('templateDownload') }}
</a-button>
<!-- 批量删除-->
<a-button type="primary" icon="delete" ghost @click="batchDel" v-has="'overseasStandard:batchDel'">{{
$t('batchDelete')
}}
</a-button>
<!-- 配置标准-->
<a-button type="primary" icon="setting" ghost @click="handleConfigStandard" v-has="'overseasStandard:configStandard'">
{{ $t('standardRegulationLibrary.configStandard') }}
</a-button>
<!-- 移出标准-->
<a-button type="primary"
icon="minus-circle"
ghost
@click="handleRemoveStandard"
v-has="'overseasStandard:removeStandard'">
{{ $t('standardRegulationLibrary.removeStandard') }}
</a-button>
</div>
<div>
<j-table
v-if="columns && columns.length > 0"
ref="tableRef"
:columns="columns"
:dataSource="dataSource"
:can-drag="true"
rowKey="id"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:pagination="ipagination"
:scroll="{x: '100%', y: yScrollHeight}"
:loading="loading"
@change="tableOnChange">
<!-- 标准编号-->
<template v-slot:standard_number="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="filePreview(record)">{{
text
}}
</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<!-- 标准名称-->
<template v-slot:standard_name="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="filePreview(record)">{{
text
}}
</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<template v-slot:operation="{text, record}">
<template v-if="operationList.length > operateMaxNum + 1">
<!-- 收藏-->
<a @click="operationClick(operationList[0],record)"
v-if="operationList[0].text === $t('standardRegulationLibrary.domesticStandard.cancelCollection')">
<i class="iconfont icon-star1" v-show="record.collectionFlag" />
<i class="iconfont icon-star" v-show="!record.collectionFlag" />
</a>
<a v-else @click="operationClick(operationList[0],record)">
<div class="operate-btn">
<!-- 查看图标-->
<i class="iconfont icon-link operate-btn-icon" v-if="operationList[0].text === $t('viewDetail')" />
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operationList[0].text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operationList[0].text === $t('delete')" />
{{ operationList[0].text }}
</div>
</a>
<a-divider type="vertical" />
<a-dropdown placement="bottomCenter">
<a-icon type="more" class="operate-icon-btn operate-icon-more" />
<a-menu slot="overlay">
<a-menu-item v-for="(operation, index) in operationList.slice(operateMaxNum)" :key="index">
<a @click="operationClick(operation,record)">
<div class="operate-btn">
<!-- 查看图标-->
<i class="iconfont icon-link operate-btn-icon" v-if="operation.text === $t('viewDetail')" />
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operation.text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operation.text === $t('delete')" />
{{ operation.text }}
</div>
</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template v-else-if="operationList.length > 0">
<template v-for="(operation, index) in operationList">
<!-- 收藏-->
<a :key="index" @click="operationClick(operationList[0],record)"
v-if="operation.text === $t('standardRegulationLibrary.domesticStandard.cancelCollection')">
<i class="iconfont icon-star1" v-show="record.collectionFlag" />
<i class="iconfont icon-star" v-show="!record.collectionFlag" />
</a>
<a v-else @click="operationClick(operation,record)" style="display: inline-block">
<div class="operate-btn">
<!-- 编辑图标-->
<i class="iconfont icon-bianji operate-btn-icon" v-if="operation.text === $t('edit')" />
<!-- 删除图标-->
<i class="iconfont icon-shanchu_ operate-btn-icon" v-if="operation.text === $t('delete')" />
{{ operation.text }}
</div>
</a>
<a-divider type="vertical" v-if="index !== operationList.length - 1" />
</template>
</template>
</template>
</j-table>
</div>
</div>
<!-- 新增编辑-->
<overseas-standard-modal ref="modalForm" @ok="modalFormOk" />
<!-- 树新增编辑-->
<overseas-system-tree-modal ref="treeModal" @ok="modalFormOk" />
<!-- 配置标准-->
<selection-overseas-standard-drawer ref="standardSelectionModal"
:node-code="selectedTreeNodeCodes[0]"
@change="continueConfigStandard" />
</a-card>
</template>
<script>
import '@assets/less/common.less'
import { ConfigurableTableMixin } from '../../../mixins/ConfigurableTableMixin'
import Search from '../../../components/customField/Search.vue'
import JTable from '../../../components/jero/JTable.vue'
import {
getOverseasStandardSearchForm,
getOverseasStandardTableHeader,
getOverseasStandardSystem,
collectionOverseasStandard,
cancelCollectionOverseasStandard,
deleteOverseasStandardSystem,
configOverseasStandard,
removeOverseasStandard,
getOverseasStandardForm,
getOverseasStandardDocumentInfo
} from '../../../api/standardRegulationLibraryApi'
import {
OperationType,
StandardSource,
StandardStatus,
StandardSystemTreeNodeType,
YesOrNoEnum
} from '../../../enums/commonEnums'
import OverseasStandardModal from './modules/OverseasStandardModal.vue'
import OverseasSystemTreeModal from './modules/OverseasSystemTreeModal.vue'
import SelectionOverseasStandardDrawer from './modules/SelectionOverseasStandardDrawer.vue'
import { postDownFile } from '../../../api/manage.js'
import { mapGetters } from 'vuex'
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { previewPdf } from '@/utils/previewPdf'
import { kkFilePreview } from '@/utils/kkFilePreview'
import { getFileInfo } from '@api/api'
export default {
name: 'OverseasStandardList',
components: {
Search,
JTable,
OverseasStandardModal,
OverseasSystemTreeModal,
SelectionOverseasStandardDrawer
},
mixins: [ConfigurableTableMixin],
data () {
return {
StandardSystemTreeNodeType,
treeInput: null, // 树查询绑定值
treeData: [],
mouseInNodeKey: null, // 鼠标悬浮的节点key值
showAction: true,
operationList: [
// 收藏
{
text: this.$t('standardRegulationLibrary.domesticStandard.cancelCollection'),
clickEvent: 'handleCollection',
has: 'overseasStandard:collection'
},
// 查看
{
text: this.$t('viewDetail'),
clickEvent: 'toDetailPage',
has: 'overseasStandard:view'
},
// 编辑
{
text: this.$t('edit'),
clickEvent: 'handleEdit',
has: 'overseasStandard:edit'
},
// 删除
{
text: this.$t('delete'),
clickEvent: 'handleDelete',
has: 'overseasStandard:delete'
}
],
getTableHeaderFunc: getOverseasStandardTableHeader,
getQueryConditionFunc: getOverseasStandardSearchForm,
url: {
list: '/laws/standard/overseas/getCommonPage',
delete: '/laws/standard/overseas/deleteByIdsAndModule',
deleteBatch: '/laws/standard/overseas/deleteByIdsAndModule',
downTemplateUrl: '/laws/standard/overseas/templateDownload', // 下载模板
exportXlsUrl: '/laws/standard/overseas/exportData', // 导出
exportZipUrl: '/laws/standard/overseas/exportDataWithFile', // 带文件导出
importExcelUrl: '/laws/standard/overseas/importExcelWithData' // 导入
},
yesValue: YesOrNoEnum.YES.value,
noValue: YesOrNoEnum.NO.value,
selectedTreeKeys: [], // 选中的树节点key
selectedTreeNodeCodes: [], // 选中树节点的code
tableSlotField: ['standard_name', 'standard_number'], // 表格中需要插槽的字段
treeLoading: false,
isCollection: false,
expandedKeys: [],
defaultSearchParams: {
standard_state: `${StandardStatus.CURRENTLY_EFFECTIVE.value},${StandardStatus.BE_IMPLEMENTED_SOON.value},${StandardStatus.RELEASE.value}`
}
}
},
computed: {
...mapGetters(['userInfo']),
importExcelUrl () {
return `${window._CONFIG.domianURL}/${this.url.importExcelUrl}`
},
// 当前用户是否管理员
isAdmin () {
const adminRoleList = window._CONFIG.adminRoleCode.split(',')
const userRoleList = this.userInfo.roleCode.split(',')
return userRoleList.some(tt => adminRoleList.includes(tt))
}
},
created () {
this.initTreeData()
},
methods: {
/**
* 获取树数据
*/
initTreeData () {
this.treeLoading = true
const params = {
nodeName: this.treeInput
}
if (!params.nodeName) {
delete params.nodeName
}
getOverseasStandardSystem(params).then(res => {
this.treeData = []
this.selectedTreeKeys = []
this.selectedTreeNodeCodes = []
this.filters.nodeCode = null
if (res.success) {
this.treeData = res.result || []
// 根节点默认展开
this.expandedKeys = [this.treeData[0].key]
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.treeLoading = false
})
},
/**
* 树节点查询
*/
handleTreeSearch () {
this.initTreeData()
},
/**
* 树节点鼠标移入
* @param key
*/
handleTreeMouseover (key) {
this.mouseInNodeKey = key
},
/**
* 树节点鼠标移出
* @param key
*/
handleTreeMouseout (key) {
if (this.mouseInNodeKey === key) {
this.mouseInNodeKey = null
}
},
/**
* 收藏/取消收藏
* @param record
*/
handleCollection ({ collectionFlag, id: standardId, standard_number: standardNumber }) {
if (this.isCollection) {
return
}
this.isCollection = true
let params
let submitFunc
// 取消收藏
if (collectionFlag) {
params = { id: standardId, standardNumber }
submitFunc = cancelCollectionOverseasStandard
} else {
params = { standardId, standardNumber }
submitFunc = collectionOverseasStandard
}
// 收藏
submitFunc(params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.isCollection = false
})
},
modalFormOk () {
this.selectedTreeKeys = []
this.filters.nodeCode = null
this.initTreeData()
// 新增/修改 成功时,重载列表
this.loadData()
// 清空列表选中
this.onClearSelected()
},
/**
* 新增树节点
* @param dataRef
*/
handleAddTreeNode ({ dataRef }) {
this.$refs.treeModal.add({ parentId: dataRef.id, parentCode: dataRef.nodeCode })
},
/**
* 编辑树节点
* @param dataRef
*/
handleEditTreeNode ({ dataRef }) {
this.$refs.treeModal.edit(dataRef)
},
/**
* 删除树节点
* @param dataRef
*/
handleDelTreeNode ({ dataRef }) {
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
deleteOverseasStandardSystem({ id: dataRef.id }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.modalFormOk()
} else {
this.$message.warning(res.message)
}
})
}
})
},
/**
* 选中树节点
* @param dataRef
*/
handleSelectTreeNode ({ dataRef }) {
this.selectedTreeKeys = [dataRef.key]
this.selectedTreeNodeCodes = [dataRef.nodeCode]
this.filters.nodeCode = dataRef.nodeCode
this.loadData(1)
},
/**
* 配置标准
*/
handleConfigStandard () {
// 请先选择二级及以下体系
if (!this.selectedTreeNodeCodes || this.selectedTreeNodeCodes.length === 0 ||
this.selectedTreeNodeCodes.includes('MyCollection') || this.selectedTreeNodeCodes.includes('A03')) {
this.$message.warn(this.$t('standardRegulationLibrary.configStandardNoTreeNode'))
return
}
this.$refs.standardSelectionModal.open()
},
/**
* 配置标准-提交
* @param dbFieldName
* @param standardIds
*/
continueConfigStandard (dbFieldName, standardIds) {
this.loading = true
const params = {
nodeCode: this.selectedTreeNodeCodes[0],
ids: standardIds
}
configOverseasStandard(params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
/**
* 移出标准
*/
handleRemoveStandard () {
// 没选择左侧树节点,需要提示“请先选择二级及以下体系”
if (!this.selectedTreeNodeCodes || this.selectedTreeNodeCodes.length === 0 || this.selectedTreeNodeCodes.includes('A03')) {
this.$message.warn(this.$t('standardRegulationLibrary.configStandardNoTreeNode'))
return
}
// 左侧节点选的是我的收藏,不可移出标准
if (this.selectedTreeNodeCodes[0] === 'MyCollection') {
this.$message.warn(this.$t('enterpriseStandardLibrary.standard.myCollectNotRemove'))
return
}
// 没有选择列表数据,需要提示“选中至少一条列表数据”
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('standardRegulationLibrary.selectLeastOneTableData'))
return
}
this.loading = true
const params = {
nodeCode: this.selectedTreeNodeCodes[0],
ids: this.selectedRowKeys.join(',')
}
removeOverseasStandard(params).then(res => {
if (res.success) {
this.$message.success(res.message)
// 判断当前删除的数据是否是最后一页的最后一条数据,如果是的话页码减一
if (this.ipagination.current > 1 && ((this.ipagination.current - 1) * this.ipagination.pageSize) + 1 === this.ipagination.total) {
this.ipagination.current -= 1
}
this.loadData()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
/**
* 跳转详情页
* @param id
* @param standardNumber
*/
toDetailPage ({ id }) {
this.$openPageNewSheet({
path: '/standardRegulationLibrary/OverseasStandardDetail',
query: {
id
}
})
},
/**
* 按顺序打开最新的pdf或word
*/
async filePreview (record) {
console.log('filePreview', record)
// 获取并处理过程稿件数据
let res = await getOverseasStandardForm({ type: 1 })
if (!res.success) {
this.$message.warn(res.message)
console.log('getDomesticStandardFormModal error:', res)
return
}
console.log('res.result', res.result)
const data = res.result || {}
const form = data
const partList = Object.keys(data)
let part
const partZh = '过程稿件'
const partEn = 'Process Manuscript'
if (partList.includes(partEn))part = partEn
if (partList.includes(partZh))part = partZh
console.log('part', part)
const processManuscript = form[part]
console.log('过程稿件', processManuscript)
// 获取并处理详情数据
res = await getOverseasStandardDocumentInfo({ id: record.id, type: 1 })
if (!res.success) {
this.$message.warn(res.message)
console.log('getDomesticStandardDetail error:', res)
return
}
const detailData = Object.assign({}, res.result || {})
console.log('detailData', detailData)
// 选择合适的文件
let file = null
const pdfFileList = []
const docFileList = []
let newestFileList = []
// 按照过程稿件顺序寻找文件
for (const formItem of processManuscript) {
const keyId = formItem.dbFieldName
const keyName = formItem.dbFieldName + '_dictText'
if (!detailData[keyId]) continue
const idArray = detailData[keyId].split(',')
const nameArray = detailData[keyName].split(',')
// 每个过程中可能有多个文件
for (let i = 0; i < idArray.length; i++) {
const id = idArray[i]
const name = nameArray[i]
var suffix = name.substring(name.lastIndexOf('.') + 1).toLowerCase()
if (suffix === 'pdf') {
pdfFileList.push({ id, name, suffix })
}
if (suffix === 'docx') {
docFileList.push({ id, name, suffix })
}
}
// 一旦一个过程中找到pdf或者doc,就可以退出
if (pdfFileList.length > 0 || docFileList.length > 0) {
break
}
}
newestFileList = pdfFileList // 默认从pdf里选最新的文件
if (pdfFileList.length === 0)newestFileList = docFileList // 如果没有pdf文件,就从doc文件里选
file = await this.selectNewestFile(newestFileList)
if (file === null) { // 没有找到文件就退出
console.log('没有找到符合要求的文件!')
this.$message.error('该标准暂无预览文件,请联系标准管理员。')
return
}
console.log('seletedFile', file)
// 预览选择的文件
const fileFullUrl = `${window._CONFIG.domianWebSocketURL}/sys/common/view/${file.id}?at=${Vue.ls.get(ACCESS_TOKEN)}&fullfilename=${file.name}`
console.log(fileFullUrl)
if (file.suffix === 'pdf') { // pdf预览
const url = previewPdf(file.id)
window.open(url)
return
}
kkFilePreview(fileFullUrl)// 其余可预览文件仍使用KKFile进行预览
},
/**
* 从文件列表里选择最新文件
* @param fileList
*/
async selectNewestFile (fileList) {
if (!fileList || fileList.length === 0) return null
if (fileList.length === 1) return fileList[0]
const newFileList = []
// 获取时间信息
for (const file of fileList) {
const res = await getFileInfo(file)
newFileList.push({ ...file, ...res.result })
}
// 排序取出最新
newFileList.sort((a, b) => b.id - a.id) // 日期只精确到天,用id更能区分
console.log('newFileList', newFileList)
return newFileList[0]
},
/**
* 重置查询
*/
searchReset (params) {
this.searchParams = Object.assign({}, params)
this.selectedRowKeys = []
this.selectedTreeKeys = []
delete this.filters.nodeCode
this.getTableHeader()
this.loadData()
},
// 导出改成用post
handleExportXls (fileName) {
if (!fileName || typeof fileName !== 'string') {
fileName = '导出文件'
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
console.log('导出参数', param)
// 加一个大的提示
const modalLoading = this.$info({
title: '提示',
content: <span>正在导出请稍候 <a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
postDownFile(this.url.exportXlsUrl, param).then((data) => {
if (!data || data.size === 0) {
this.$message.warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName + '.xls')
} else {
const url = window.URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + '.xls')
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
// 带文件导出
handleFileExport (fileName) {
if (!fileName || typeof fileName !== 'string') {
fileName = '导出文件'
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
param.module = StandardSource.OVERSEAS.value
console.log('导出参数', param)
// 加一个大的提示
const modalLoading = this.$info({
title: '提示',
content: <span>正在导出请稍候 <a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
postDownFile(this.url.exportZipUrl, param).then((data) => {
if (!data) {
this.$message.warning('文件下载失败')
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName + '.zip')
} else {
const url = window.URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
// }
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
/**
* 新增-非管理员用户跳转流程发起页面,不能修改操作类型
*/
handleAdd () {
if (!this.isAdmin) {
this.$router.push({
path: '/workCenter/StandardEntryOrChangeProcess',
query: {
source: StandardSource.OVERSEAS.value, // 海外标准
operateType: OperationType.ENTRY.value // 入库
}
})
return
}
this.$refs.modalForm.add()
this.$refs.modalForm.title = this.$t('newlyAdded')
this.$refs.modalForm.disableSubmit = false
},
handleEdit (record) {
if (!this.isAdmin) {
this.$router.push({
path: '/workCenter/StandardEntryOrChangeProcess',
query: {
source: StandardSource.OVERSEAS.value, // 海外标准
operateType: OperationType.CHANGE.value, // 变更
standardId: record.id // 标准id
}
})
return
}
this.$refs.modalForm.edit(record)
this.$refs.modalForm.title = this.$t('edit')
this.$refs.modalForm.disableSubmit = false
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
/deep/ .ant-tree li span.ant-tree-switcher.ant-tree-switcher-noop {
color: #1D2129;
}
.parent-node-icon {
color: #1D2129;
font-size: 16px;
margin-right: 10px;
}
</style>
@@ -0,0 +1,143 @@
<template>
<a-drawer
:title="title"
:width="width"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
:maskClosable="false"
destroyOnClose
class="custom-drawer-style"
>
<div class="custom-drawer-style-scroll">
<a-spin :spinning="confirmLoading" style="width: 100%;height:100%">
<add-form ref="addForm"
:flag="StandardSource.OVERSEAS.value"
:get-form-func="getFormFunc"
:get-document-info-func="getDocumentInfoFunc"
:special-placeholder="specialPlaceholder"
:default-value="defaultValue"
:disabled-field-list="disabledField"
:open-selected-all-field-list="openSelectedAllFieldList"
:exclude-standard-fields="excludeStandardFields"
@submitFormData="submitFormData" />
</a-spin>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel" style="margin-bottom: 0;" :loading="confirmLoading">{{ $t('close') }}</a-button>
<a-button @click="handleOk" type="primary" style="margin-bottom: 0;" :loading="confirmLoading">
{{ $t('preservation') }}
</a-button>
</div>
</a-drawer>
</template>
<script>
import AddForm from '../../../../components/customField/AddForm.vue'
import {
getOverseasStandardForm,
getOverseasStandardDocumentInfo,
addOverseasStandard,
editOverseasStandard
} from '../../../../api/standardRegulationLibraryApi'
import { StandardSource } from '../../../../enums/commonEnums.js'
export default {
name: 'OverseasStandardModal',
components: { AddForm },
data () {
return {
StandardSource,
visible: false,
title: '',
width: 800,
// 存储表单的数据
form: {},
confirmLoading: false,
getFormFunc: getOverseasStandardForm,
getDocumentInfoFunc: getOverseasStandardDocumentInfo,
// 特殊的placeholder
specialPlaceholder: {
standard_number_temp: `${this.$t('standardRegulationLibrary.inputExample')}7258`
},
defaultValue: {
year_number: new Date().getFullYear() + ''
},
// 数据字典多选,需要全选功能的字段
openSelectedAllFieldList: [
'applicable_vehicle', // 适用车型
'dynamic_type' // 动力类型
],
isEdit: null // 是否编辑
}
},
computed: {
// 不可编辑的字段
disabledField () {
console.log(this.isEdit)
if (this.isEdit) {
// 标准编号,被代替标准号,被引用标准号
return ['standard_class', 'year_number', 'standard_number_temp', 'replaced_by_standard_number', 'referenced_standard']
}
return ['replaced_by_standard_number', 'referenced_standard']
},
excludeStandardFields () {
if (this.isEdit) {
return ['substitute_standard_number', 'reference_standard']
}
return []
}
},
methods: {
add () {
this.visible = true
this.isEdit = false
this.$nextTick(() => {
this.$refs.addForm.add()
})
},
edit (record) {
this.visible = true
this.isEdit = true
this.$nextTick(() => {
this.$refs.addForm.edit(record)
})
},
handleOk () {
this.$refs.addForm.submit()
},
// 表单提交的回调,获取表单数据
submitFormData (formInline) {
this.confirmLoading = true
let submitFunc
if (formInline.id) {
submitFunc = editOverseasStandard
} else {
submitFunc = addOverseasStandard
}
submitFunc(formInline).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,103 @@
<template>
<j-modal
:title="title"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('standardRegulationLibrary.nodeName')">
<a-input :placeholder="$t('pleaseEnter') + $t('standardRegulationLibrary.nodeName')"
:maxLength="50"
v-decorator="['nodeName', validatorRules.nodeName]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import { addOverseasStandardSystem, editOverseasStandardSystem } from '../../../../api/standardRegulationLibraryApi.js'
export default {
name: 'OverseasSystemTreeModal',
data () {
return {
title: this.$t('operation'),
width: 800,
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 节点名称
nodeName: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('standardRegulationLibrary.nodeName') }],
validateTrigger: 'blur'
}
}
}
},
methods: {
add (parentInfo) {
this.edit(parentInfo)
},
edit (record) {
this.form.resetFields()
this.model = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
close () {
this.visible = false
},
handleOk () {
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
const formData = Object.assign(this.model, values)
formData.nodeOrder = '0'
let submitFunc
if (this.model.id) {
submitFunc = editOverseasStandardSystem
} else {
submitFunc = addOverseasStandardSystem
}
submitFunc(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel () {
this.close()
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,238 @@
<template>
<a-drawer
:title="$t('standardSelect.standardSelection')"
:maskClosable="false"
:width="1000"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
class="custom-drawer-style">
<div class="custom-drawer-style-scroll">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :sm="8">
<a-form-item :label="$t('standardSelect.standardNumOrName')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter')+$t('standardSelect.standardNumOrName')"
v-model="queryParam.standardNumberOrName"></a-input>
</a-form-item>
</a-col>
<div style="float: right;overflow: hidden;margin-right: 41px;margin-bottom: 20px"
class="table-page-search-submitButtons">
<a-button class="box-button" style="margin-left: 8px" @click="searchReset">{{ $t('reset') }}</a-button>
<a-button class="box-button" style="margin-left: 8px" type="primary" @click="searchQuery">{{
$t('query')
}}
</a-button>
</div>
</a-row>
</a-form>
</div>
<a-table
:columns="columns"
rowKey="serial_number"
:scroll="{x: 900}"
:data-source="dataList"
:pagination="ipagination"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:loading="loading"
@change="handleTableChange">
<!-- 标准编号标准名称跳转详情-->
<template v-slot:detail="text, record">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text can-click-table-text" v-if="text || text === 0" @click="toDetailPage(record)">{{ text }}</div>
<div v-else class="table-text">{{ global.emptyLine }}</div>
</a-tooltip>
</template>
<template slot="text" slot-scope="text">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div class="table-text">{{ text || text === 0 ? text : global.emptyLine }}</div>
</a-tooltip>
</template>
</a-table>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button @click="handleSubmit" type="primary" :loading="confirmLoading">{{ $t('submit') }}</a-button>
</div>
</a-drawer>
</template>
<script>
import { getDomesticStandardNoSystem } from '../../../../api/standardRegulationLibraryApi.js'
import { StandardSource } from '../../../../enums/commonEnums.js'
export default {
name: 'SelectionOverseasStandardDrawer',
props: {
// 选中节点code
nodeCode: {
type: String,
required: false,
default: null
},
query: {
type: Object,
required: false,
default: () => {
return {}
}
}
},
data () {
return {
visible: false,
confirmLoading: false,
labelCol: {
sm: 8
},
wrapperCol: {
sm: 14
},
selectedRowKeys: [],
selectedRowList: [],
loading: false,
queryParam: {},
/* 分页参数 */
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '30', '50', '100', '150', '200'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' ' + this.$t('total') + ' ' + total + ' ' + this.$t('strip')
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
columns: [
// 标准号
{
title: this.$t('standardSelect.standardNumber'),
dataIndex: 'standardNumber',
align: 'center',
width: 150,
scopedSlots: { customRender: 'detail' }
},
// 标准名称
{
title: this.$t('standardSelect.standardName'),
dataIndex: 'standardName',
align: 'center',
width: 150,
scopedSlots: { customRender: 'detail' }
},
// 发布日期
{
title: this.$t('standardSelect.releaseDate'),
dataIndex: 'releaseDate',
align: 'center',
width: 120,
scopedSlots: { customRender: 'text' }
},
// 标准状态
{
title: this.$t('projectLibrary.vehicleItemLibrary.standardState'),
dataIndex: 'standardState_dictText',
align: 'center',
width: 120,
scopedSlots: { customRender: 'text' }
}
],
dataList: [],
url: {
searchList: 'document/bussDocumentLibraryEO/queryCondition' // 搜索字段
}
}
},
methods: {
open () {
this.visible = true
this.queryParam = {}
this.replacePage()
},
// 获取表格数据
replacePage () {
const query = {
...this.queryParam,
pageNo: this.ipagination.current,
pageSize: this.ipagination.pageSize,
nodeCode: this.nodeCode,
source: StandardSource.OVERSEAS.value
}
this.selectedRowKeys = []
this.loading = true
getDomesticStandardNoSystem(query).then((res) => {
if (res.success) {
this.dataList = res.result.records
this.ipagination.total = res.result.total
this.selectedRowKeys = this.standard[this.query.db_field_name] ? this.standard[this.query.db_field_name].split(',') : []
} else {
this.dataList = []
}
}).finally(() => {
this.loading = false
})
},
searchQuery () {
this.replacePage()
},
searchReset () {
this.queryParam = {}
this.replacePage()
},
// 表格选择改变
onSelectChange (value, row) {
this.selectedRowKeys = value
this.selectedRowList = row
},
handleCancel () {
this.visible = false
},
handleSubmit () {
const serialNumber = []
const replaceStandardId = []
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
// let content = JSON.parse(JSON.stringify(this.selectedRowList))
this.selectedRowList.forEach(res => {
serialNumber.push(res.serial_number)
replaceStandardId.push(res.id)
})
this.$emit('input', serialNumber.join(','))
this.$emit('change', this.query.dbFieldName, replaceStandardId.join(','))
// this.$emit('changecontent', this.content)
this.visible = false
} else {
this.$message.warning(this.$t('selectLeastOne'))
}
},
/**
* 跳转详情页
* @param id
*/
toDetailPage ({ id }) {
this.$openPageNewSheet({
path: '/standardRegulationLibrary/OverseasStandardDetail',
query: {
id
}
})
},
handleTableChange (pagination) {
this.ipagination = pagination
this.replacePage()
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,413 @@
<template>
<a-card :bordered="false" class="page-left-right-layout">
<!-- 树部分-->
<div class="page-left-box">
<a-input-search v-model="treeInput" class="tree-search"
:placeholder="$t('standardRegulationLibrary.domesticStandard.treeSearchPlaceholder')"
@search="handleTreeSearch" />
<div class="page-tree-box page-tree-box-has-search">
<a-spin :spinning="treeLoading">
<a-tree :show-line="true" :show-icon="true" :tree-data="treeData" :selected-keys="selectedTreeKeys">
<template #title="record">
<div class="tree-operate-node"
:class="{'tree-operate-node-selected': selectedTreeKeys.includes(record.id)}"
@mouseenter="handleTreeMouseover(record.id)"
@mouseleave="handleTreeMouseout(record.id)"
@click="handleSelectTreeNode(record)">
<a-icon class="parent-node-icon"
type="folder"
v-if="record.dataRef.children && record.dataRef.children.length > 0" />
<a-tooltip>
<template #title>
{{ record.folderName }}
</template>
<span class="tree-node-custom-title">{{ record.folderName }}</span>
</a-tooltip>
<div class="tree-operate-node-btn-box"
:class="{'tree-operate-node-btn-box-hide': record.id !== mouseInNodeKey}"
v-if="hasManagePermission(record)">
<!--新增同级-->
<a-button icon="plus"
:title="$t('standardRegulationLibrary.profileCenter.addAPeer')"
class="tree-operate-node-btn"
@click.stop="handleAddPeerFolder(record)"
v-has="'profileCenter:addPeer'" />
<!--新增子级-->
<a-button class="tree-operate-node-btn"
:title="$t('standardRegulationLibrary.profileCenter.newChild')"
@click.stop="handleAddChildrenFolder(record)"
v-has="'profileCenter:addChildren'">
<i class="iconfont icon-wenjian-tianjia" />
</a-button>
<!--编辑-->
<a-button class="tree-operate-node-btn"
:title="$t('edit')"
@click.stop="handleEditTreeNode(record)"
v-has="'profileCenter:editFolder'">
<i class="iconfont icon-bianji" />
</a-button>
<!--删除根节点不能删除-->
<a-button v-if="record.defaultFolder !== '1'"
class="tree-operate-node-btn"
:title="$t('delete')"
@click.stop="handleDelTreeNode(record)"
v-has="'profileCenter:deleteFolder'">
<i class="iconfont icon-shanchu_" />
</a-button>
</div>
</div>
</template>
</a-tree>
</a-spin>
</div>
</div>
<!-- 表格部分-->
<div class="page-right-box">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<!--文件名称-->
<a-col :md="6" :sm="12">
<a-form-item :label="$t('fileName')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('fileName')" v-model="queryParam.fileName"></a-input>
</a-form-item>
</a-col>
<!--上传人-->
<a-col :md="6" :sm="12">
<a-form-item :label="$t('uploadedBy')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter') + $t('uploadedBy')" v-model="queryParam.uploader"></a-input>
</a-form-item>
</a-col>
<!--上传时间-->
<a-col :md="6" :sm="12">
<a-form-item :label="$t('uploadTime')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-range-picker
:placeholder="[$t('pleaseSelectTime'), $t('pleaseSelectTime')]"
style="width: 100%"
showTime
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
v-model="queryParam.uploadTime">
</a-range-picker>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<div style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary"
@click="searchQuery"
icon="search"
style="margin-left: 8px"
v-has="'profileCenter:table'">
{{ $t('query') }}
</a-button>
<a-button type="primary" @click="searchReset" icon="reload" ghost>{{ $t('reset') }}</a-button>
</div>
</a-col>
</a-row>
</a-form>
</div>
<div class="table-operator">
<!-- 新增-->
<a-button icon="plus" type="primary" @click="handleAdd" v-has="'profileCenter:table'">{{ $t('newlyAdded') }}</a-button>
<!-- 批量删除-->
<a-button type="primary" icon="delete" ghost @click="batchDel" v-has="'profileCenter:table'">
{{ $t('batchDelete') }}
</a-button>
</div>
<div>
<j-table
:columns="columns"
:dataSource="dataSource"
:can-drag="true"
rowKey="id"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:pagination="ipagination"
:scroll="{x: '100%', y: yScrollHeight}"
:loading="loading"
:operation-list="operationList"
@change="handleTableChange"
@operationClick="operationClick">
</j-table>
</div>
</div>
<!--表格数据新增编辑-->
<profile-center-modal ref="modalForm" @ok="modalFormOk" />
<!--树节点新增编辑-->
<profile-center-tree-modal ref="treeModal" @ok="modalFormOk" />
</a-card>
</template>
<script>
import JTable from '../../../components/jero/JTable.vue'
import { JeroListMixin } from '../../../mixins/JeroListMixin.js'
import { deleteProfileCenterTree, getProfileCenterTree } from '../../../api/standardRegulationLibraryApi.js'
import ProfileCenterModal from './modules/ProfileCenterModal.vue'
import ProfileCenterTreeModal from './modules/ProfileCenterTreeModal.vue'
import { filterObj } from '../../../utils/util'
import { downloadFile } from '../../../api/manage'
import { mapGetters } from 'vuex'
export default {
name: 'ProfileCenterList',
components: { JTable, ProfileCenterModal, ProfileCenterTreeModal },
mixins: [JeroListMixin],
data () {
return {
treeInput: null, // 树查询绑定值
treeData: [],
mouseInNodeKey: null, // 鼠标悬浮的节点key值
columns: [
// 文件名称
{
dataIndex: 'fileName',
title: this.$t('fileName'),
width: 150
},
// 文件说明
{
dataIndex: 'fileDescription',
title: this.$t('fileDeclaration'),
width: 150
},
// 上传人
{
dataIndex: 'uploader',
title: this.$t('uploadedBy'),
width: 150
},
// 上传时间
{
dataIndex: 'createTime',
title: this.$t('uploadTime'),
width: 150
},
// 操作
{
title: this.$t('operation'),
fixed: 'right',
width: 150,
scopedSlots: { customRender: 'action' }
}
],
operationList: [
// 下载
{
text: this.$t('download'),
clickEvent: 'handleDownload',
has: 'profileCenter:table'
},
// 编辑
{
text: this.$t('edit'),
clickEvent: 'handleEdit',
has: 'profileCenter:table',
show: (record) => {
return record.authManageTag
}
},
// 删除
{
text: this.$t('delete'),
clickEvent: 'handleDelete',
has: 'profileCenter:table',
show: (record) => {
return record.authManageTag
}
}
],
url: {
list: '/laws/dataCenter/lawsDataCenterFile/page',
delete: '/laws/dataCenter/lawsDataCenterFile/delete',
deleteBatch: '/laws/dataCenter/lawsDataCenterFile/deleteBatch'
},
selectedTreeKeys: [], // 选中的树节点key
treeLoading: false
}
},
computed: {
...mapGetters(['userInfo'])
},
created () {
this.initTreeData()
},
methods: {
/**
* 获取树数据
*/
initTreeData () {
this.treeLoading = true
const params = {
folderName: this.treeInput
}
if (!params.folderName) {
delete params.folderName
}
getProfileCenterTree(params).then(res => {
this.treeData = []
this.selectedTreeKeys = []
this.selectedTreeNodeCodes = []
this.filters.nodeCode = null
if (res.success) {
this.treeData = res.result || []
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.treeLoading = false
})
},
handleAdd: function () {
if (!this.selectedTreeKeys||this.selectedTreeKeys.length === 0) {
this.$message.warning(this.$t('standardRegulationLibrary.profileCenter.pleaseSelectTheDirectoryOnTheLeft'))
return
}
const folderId = this.selectedTreeKeys && this.selectedTreeKeys.length > 0 ? this.selectedTreeKeys.join(',') : null
this.$refs.modalForm.add({ folderId })
this.$refs.modalForm.title = this.$t('newlyAdded')
this.$refs.modalForm.disableSubmit = false
},
/**
* 树节点查询
*/
handleTreeSearch () {
this.initTreeData()
},
/**
* 树节点鼠标移入
* @param key
*/
handleTreeMouseover (key) {
this.mouseInNodeKey = key
},
/**
* 树节点鼠标移出
* @param key
*/
handleTreeMouseout (key) {
if (this.mouseInNodeKey === key) {
this.mouseInNodeKey = null
}
},
/**
* 选中树节点
* @param dataRef
*/
handleSelectTreeNode ({ dataRef }) {
this.selectedTreeKeys = [dataRef.id]
this.loadData(1)
},
modalFormOk () {
this.selectedTreeKeys = []
this.initTreeData()
// 新增/修改 成功时,重载列表
this.loadData()
// 清空列表选中
this.onClearSelected()
},
/**
* 新增同级节点
* @param dataRef
*/
handleAddPeerFolder ({ dataRef }) {
this.$refs.treeModal.title = this.$t('newlyAdded')
this.$refs.treeModal.add({ parentId: dataRef.parentId }, true)
},
/**
* 新增子节点
* @param dataRef
*/
handleAddChildrenFolder ({ dataRef }) {
this.$refs.treeModal.title = this.$t('newlyAdded')
this.$refs.treeModal.add({ parentId: dataRef.id }, false)
},
/**
* 编辑树节点
* @param dataRef
*/
handleEditTreeNode ({ dataRef }) {
this.$refs.treeModal.title = this.$t('edit')
this.$refs.treeModal.edit(dataRef)
},
/**
* 删除树节点
* @param dataRef
*/
handleDelTreeNode ({ dataRef }) {
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
deleteProfileCenterTree({ id: dataRef.id }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.modalFormOk()
} else {
this.$message.warning(res.message)
}
})
}
})
},
/**
* 重置查询
*/
searchReset () {
this.queryParam = {}
this.selectedTreeKeys = []
this.loadData(1)
},
getQueryParams () {
// 获取查询条件
const sqp = {}
if (this.superQueryParams) {
sqp.superQueryParams = encodeURI(this.superQueryParams)
sqp.superQueryMatchType = this.superQueryMatchType
}
const param = Object.assign(sqp, this.queryParam, this.isorter, this.filters)
param.field = this.getQueryField()
param.pageNo = this.ipagination.current
param.pageSize = this.ipagination.pageSize
param.folderId = this.selectedTreeKeys.join(',')
Object.keys(param).forEach(val => {
if (param[val] instanceof Array) {
param[val] = param[val].join(',')
}
})
return filterObj(param)
},
handleDownload ({ id, fileName }) {
downloadFile(`/laws/dataCenter/lawsDataCenterFile/download?id=${id}`, fileName)
},
hasManagePermission ({ authManageIds, ownerId }) {
const adminRoleList = window._CONFIG.adminRoleCode.split(',')
const userRoleList = this.userInfo.roleCode.split(',')
const isAdmin = userRoleList.some(tt => adminRoleList.includes(tt))
if (isAdmin) {
return true
}
const authManageArr = (authManageIds || '').split(',')
if (authManageArr.includes(this.userInfo.id) || ownerId === this.userInfo.id) {
return true
}
return false
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.tree-operate-node-selected {
background-color: #ffd9d1 !important;
}
/deep/ .table-page-search-wrapper .ant-form-inline .ant-form-item > .ant-form-item-label {
min-width: 60px;
}
</style>
@@ -0,0 +1,151 @@
<template>
<j-modal
:title="title"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<!--文件名称-->
<!--<a-form-item :label="$t('fileName')" :labelCol="labelCol" :wrapperCol="wrapperCol">-->
<!-- <a-input :placeholder="$t('pleaseEnter') + $t('fileName')"-->
<!-- @change="event => event.target.value = event.target.value.trim()"-->
<!-- :maxLength="50"-->
<!-- v-decorator="['fileName', validatorRules.fileName]" />-->
<!--</a-form-item>-->
<!--所属类型-->
<!--<a-form-item :label="$t('standardRegulationLibrary.profileCenter.typeOfOwnership')" :labelCol="labelCol" :wrapperCol="wrapperCol">-->
<!-- <a-tree-select v-decorator="['title', validatorRules.title]"-->
<!-- :getPopupContainer="triggerNode=> triggerNode.parentNode"-->
<!-- style="width: 100%"-->
<!-- :tree-data="typeOfOwnershipTreeData"-->
<!-- :label-in-value="false"-->
<!-- :placeholder="$t('pleaseSelect')+$t('standardRegulationLibrary.profileCenter.typeOfOwnership')" />-->
<!--</a-form-item>-->
<!--上传资料-->
<a-form-item :label="$t('standardRegulationLibrary.profileCenter.uploadData')"
:labelCol="labelCol"
:wrapperCol="wrapperCol">
<j-upload v-decorator="['fileId', validatorRules.fileId]" return-id :disabled="!!modal.id" multiple />
</a-form-item>
<!--推送范围-->
<a-form-item :label="$t('standardRegulationLibrary.dynamicMessage.pushRange')"
:labelCol="labelCol"
:wrapperCol="wrapperCol">
<user-selection v-decorator="['pushRangeIds', validatorRules.pushRangeIds]"
:name-str="modal.pushRangeIds_dictText"
type="checkbox"
:placeholder="$t('pleaseSelect')+$t('standardRegulationLibrary.dynamicMessage.pushRange')" />
</a-form-item>
<!--文件说明-->
<a-form-item :label="$t('fileDeclaration')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input type="textarea"
:placeholder="$t('pleaseEnter') + $t('fileDeclaration')"
:maxLength="500"
v-decorator="['fileDescription', validatorRules.fileDescription]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import UserSelection from '../../../../components/selection/UserSelection.vue'
import { addProfileCenter, editProfileCenter } from '../../../../api/standardRegulationLibraryApi.js'
export default {
name: 'ProfileCenterModal',
components: { UserSelection },
data () {
return {
title: this.$t('newlyAdded'),
width: 600,
visible: false,
confirmLoading: false,
modal: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 上传资料
fileId: {
rules: [{ required: true, message: this.$t('uploadFile.pleaseUpload') + this.$t('uploadFile.file') }],
validateTrigger: 'change'
},
// 推送范围
pushRangeIds: {
rules: [{
required: false,
message: this.$t('pleaseSelect') + this.$t('standardRegulationLibrary.dynamicMessage.pushRange')
}],
validateTrigger: 'change'
},
// 文件说明
fileDescription: {
rules: [{ required: false, message: this.$t('pleaseEnter') + this.$t('fileDeclaration') }],
validateTrigger: 'blur'
}
},
typeOfOwnershipTreeData: [] // 所属类型树形下拉
}
},
methods: {
add (params) {
this.modal = params
this.visible = true
},
edit (record) {
this.visible = true
this.modal = Object.assign({}, record)
this.$nextTick(() => {
this.form.setFieldsValue(this.modal)
})
},
handleOk () {
this.form.validateFields((errors, values) => {
if (!errors) {
this.confirmLoading = true
let submitFunc
if (this.modal.id) {
submitFunc = editProfileCenter
} else {
submitFunc = addProfileCenter
}
const formData = Object.assign(this.modal, values)
submitFunc(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,158 @@
<template>
<j-modal
:title="title"
:maskClosable="false"
:width="width"
:visible="visible"
:confirm-loading="confirmLoading"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<!--文件夹名称-->
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('treeRight.folderName')">
<a-input :placeholder="$t('pleaseEnter') + $t('treeRight.folderName')"
:maxLength="50"
v-decorator="['folderName', validatorRules.folderName]" />
</a-form-item>
<!--管理权限-->
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('treeRight.administrativePrivileges')">
<user-selection :placeholder="$t('pleaseSelect') + $t('treeRight.administrativePrivileges')"
type="checkbox"
:name-str="model.authManageIdsDictText"
v-decorator="['authManageIds', validatorRules.authManageIds]" />
</a-form-item>
<!--查看权限-->
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('treeRight.checkPermissions')">
<user-selection :placeholder="$t('pleaseSelect') + $t('treeRight.checkPermissions')"
type="checkbox"
:disabled="model.defaultFolder === '1'"
:name-str="model.authViewIdsDictText"
v-decorator="['authViewIds', validatorRules.authViewIds]" />
</a-form-item>
<!--文件夹顺序-->
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('treeRight.folderOrder')">
<a-input :placeholder="$t('pleaseEnter') + $t('treeRight.folderOrder')"
:maxLength="50"
type="number"
v-decorator="['sort', validatorRules.sort]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import { addProfileCenterTree, editProfileCenterTree, addChildrenFolder } from '../../../../api/standardRegulationLibraryApi.js'
import UserSelection from '../../../../components/selection/UserSelection'
export default {
name: 'ProfileCenterTreeModal',
components: { UserSelection },
data () {
return {
title: this.$t('operation'),
width: 800,
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 节点名称
folderName: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('treeRight.folderName') }],
validateTrigger: 'blur'
},
// 管理权限
authManageIds: {
rules: [{ required: false, message: this.$t('pleaseSelect') + this.$t('treeRight.administrativePrivileges') }],
validateTrigger: 'change'
},
// 查看权限
authViewIds: {
rules: [{ required: false, message: this.$t('pleaseSelect') + this.$t('treeRight.checkPermissions') }],
validateTrigger: 'change'
},
// 顺序
sort: {
rules: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('treeRight.folderOrder') },
{ validator: this.validateNumber }
],
validateTrigger: 'blur'
}
},
peerOrNot: false // 是否同级
}
},
methods: {
add (parentInfo, peerOrNot) {
this.peerOrNot = peerOrNot
console.log(this.peerOrNot)
this.edit(parentInfo)
},
edit (record) {
this.form.resetFields()
this.model = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
close () {
this.visible = false
},
handleOk () {
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
const formData = Object.assign(this.model, values)
formData.nodeOrder = '0'
let submitFunc
if (this.model.id) {
submitFunc = editProfileCenterTree
} else if (this.peerOrNot) {
submitFunc = addProfileCenterTree
} else {
submitFunc = addChildrenFolder
}
submitFunc(formData).then(res => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel () {
this.close()
},
validateNumber (rule, value, callback) {
if (!value || new RegExp(/^[0-9]*[1-9][0-9]*$/).test(value)) {
callback()
} else {
callback(this.$t('pleaseEnterAPositiveInteger'))
}
}
}
}
</script>
<style scoped lang="less">
</style>