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,342 @@
<template>
<internal-detail-page :title="$route.meta.title" :loading="loading">
<template v-slot:titleRightCustom>
<a @click="handleToggle" style="margin-left: 8px">
{{ toggleStatus ? $t('putAway') : $t('open') }}
<a-icon :type="toggleStatus ? 'up' : 'down'" />
</a>
</template>
<div class="detail-page-part-form" v-show="toggleStatus">
<!--标准名称-->
<div class="detail-page-part-form-item">
<label>{{ $t('standardName') }}</label>
<span class="can-click-table-text" @click="toDetailPage">{{ detailFormData.standardNameNumber }}</span>
</div>
<!--附件-->
<div class="detail-page-part-form-item">
<label>{{ $t('businessSupport.questionAnswer.attach') }}</label>
<file-echo :operate-fixed-right="false" :file-ids="detailFormData.standardTextFileId" :can-download="false" />
</div>
<!--流程稿件-->
<div class="detail-page-part-form-item">
<label>{{ $t('businessSupport.askForAdvice.processManuscript') }}</label>
<file-echo :operate-fixed-right="false" :file-ids="detailFormData.relatedFile" :can-download="false" />
</div>
<!--征求意见周期-->
<div class="detail-page-part-form-item">
<label>{{ $t('businessSupport.askForAdvice.consultationCycle') }}</label>
<span>{{ detailFormData.consultationPeriod }}</span>
</div>
</div>
<div class="table-operator">
<!--导出-->
<a-button icon="upload"
type="primary"
ghost
v-has="'askForAdvice:detail:export'"
@click="handleExportXls($t('businessSupport.askForAdvice.detailsOfComments'), '.xlsx')">
{{ $t('export') }}
</a-button>
</div>
<div>
<j-table
ref="table"
size="middle"
:columns="columns"
:data-source="dataSource"
rowKey="id"
:can-drag="true"
:loading="loading"
:pagination="ipagination"
:scroll="{x: '100%'}"
@change="handleTableChange">
<!--修改前修改后修改理由弹框显示内容-->
<template v-slot:modalDetail="{text, record}">
<div class="table-text" @click="showContent(text)" v-if="text">{{ text }}</div>
<div v-else>{{ global.emptyLine }}</div>
</template>
<template v-slot:file="{text}">
<file-echo :file-ids="text" :operate-fixed-right="false" :can-download="false" v-if="text" />
<div v-else>{{ global.emptyLine }}</div>
</template>
</j-table>
</div>
<text-content-modal ref="textContentModal" />
</internal-detail-page>
</template>
<script>
import InternalDetailPage from '../../../components/InternalDetailPage'
import FileEcho from '../../../components/FileEcho'
import { downFile } from '../../../api/manage'
import JTable from '../../../components/jero/JTable'
import { JeroListMixin } from '../../../mixins/JeroListMixin'
import { queryAskForAdviceDetail } from '../../../api/businessSupport'
import { StandardSource } from '../../../enums/commonEnums'
import TextContentModal from './modules/TextContentModal'
export default {
name: 'AskForAdviceDetail',
components: { JTable, FileEcho, InternalDetailPage, TextContentModal },
mixins: [JeroListMixin],
data () {
return {
toggleStatus: true,
disableMixinCreated: true,
loading: false,
columns: [
{
title: this.$t('serialNumber'),
dataIndex: '',
key: 'rowIndex',
align: 'center',
width: 80,
customRender: function (t, r, index) {
return parseInt(index) + 1
}
},
{ // 条款号
title: this.$t('workCenter.enStandardRevision.clauseNumber'),
width: 180,
align: 'center',
dataIndex: 'chapterNumber',
scopedSlots: { customRender: 'text' }
},
{ // 条款名称
title: this.$t('docTool.split.clauseName'),
width: 180,
align: 'center',
dataIndex: 'chapterName',
scopedSlots: { customRender: 'text' }
},
{ // 修改意见内容
title: this.$t('workCenter.standardConsultationProcess.reasonForRevision'),
children: [
{ // 修改前
title: this.$t('workCenter.enStandardChange.beforeUpdate'),
align: 'center',
width: 180,
dataIndex: 'modificationBefore',
scopedSlots: { customRender: 'modalDetail' }
},
{ // 修改后
title: this.$t('workCenter.enStandardChange.afterUpdate'),
align: 'center',
width: 180,
dataIndex: 'modificationAfter',
scopedSlots: { customRender: 'modalDetail' }
},
{ // 修改理由
title: this.$t('workCenter.enStandardChange.updateReason'),
align: 'center',
width: 180,
dataIndex: 'modificationReason',
scopedSlots: { customRender: 'modalDetail' }
}
]
},
{ // 提出部门
title: this.$t('workCenter.enStandardChange.proposingDepartment'),
align: 'center',
width: 180,
dataIndex: 'depart',
scopedSlots: { customRender: 'text' }
},
{ // 提出人
title: this.$t('workCenter.enStandardChange.introducer'),
align: 'center',
width: 180,
dataIndex: 'designEngineerName',
scopedSlots: { customRender: 'text' }
},
{ // 处理意见
title: this.$t('workCenter.enStandardRevision.handlingSuggestion'),
align: 'center',
width: 180,
dataIndex: 'isAdopt_dictText'
},
// 依据描述
{
dataIndex: 'basisDescription',
title: this.$t('projectLibrary.specialProjectLibrary.basisDescription'),
width: 180
},
// 佐证材料
{
dataIndex: 'basisFile',
title: this.$t('projectLibrary.specialProjectLibrary.supportingMaterial'),
width: 180,
scopedSlots: { customRender: 'file' }
}
],
/* 分页参数 */
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
},
detailFormData: {} // 上方表单的数据
}
},
created () {
this.initDetailData()
},
methods: {
initDetailData () {
this.loading = true
const params = {
pageNo: this.ipagination.current,
pageSize: this.ipagination.pageSize,
businessId: this.$route.query.id
}
queryAskForAdviceDetail(params).then(res => {
if (res.success) {
// 处理表格数据
const tableResult = res.result.processFbConsultationList
this.dataSource = tableResult.records || []
if (tableResult.total) {
this.ipagination.total = tableResult.total
} else {
this.ipagination.total = 0
}
// 处理表单数据
this.detailFormData = res.result.processFbStandardConsultation || {}
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleToggle () {
this.toggleStatus = !this.toggleStatus
},
handleExportXls (fileName, fileSuffix = '.xlsx') {
if (!fileName || typeof fileName !== 'string') {
fileName = '导出文件'
}
const param = this.getQueryParams()
param.businessId = this.$route.query.id
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'
})
downFile('/laws/consultation/exportExcel', param).then((data) => {
if (!data) {
this.$message.warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data], { type: 'application/vnd.ms-excel' }), fileName + fileSuffix)
} else {
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.ms-excel' }))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + fileSuffix)
console.log(fileName + fileSuffix)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
handleTableChange (pagination, filters, sorter) {
// 分页、排序、筛选变化时触发
if (Object.keys(sorter).length > 0) {
this.isorter.column = sorter.order ? sorter.field : 'createTime'
this.isorter.order = sorter.order === 'ascend' ? 'asc' : 'desc'
}
this.ipagination = pagination
this.initDetailData()
},
/**
* 跳转标准详情
*/
toDetailPage () {
const source = this.detailFormData.source
const standardId = this.detailFormData.standardId
let path
// 根据来源跳转不同的详情页
switch (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: standardId
}
this.$openPageNewSheet({
path, query
})
},
showContent (text) {
this.$refs.textContentModal.open(text)
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.detail-page-part-form {
padding: 0;
}
.detail-page-part-form-item {
width: 100%;
label {
width: 6.5rem;
}
/deep/ .file-info {
font-size: 16px;
}
}
.can-click-table-text {
color: @primary-color !important;
}
</style>
@@ -0,0 +1,134 @@
<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('businessSupport.askForAdvice.standardNameNumber')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.askForAdvice.standardNameNumber')"
v-model="queryParam.standardNameNumber" />
</a-form-item>
</a-col>
<!--征求意见周期-->
<a-col :md="6" :sm="12">
<a-form-item :label="$t('businessSupport.askForAdvice.consultationCycle')">
<a-range-picker
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style='margin-left: -1px'
v-model="queryParam.consultationPeriodList"
:disabled="false" />
</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="'askForAdvice: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>
<j-table
ref="table"
size="middle"
:columns="columns"
:data-source="dataSource"
rowKey="id"
:can-drag="true"
:loading="loading"
:pagination="ipagination"
:scroll="{x: '100%'}"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
@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>
</j-table>
</div>
</a-card>
</template>
<script>
import { JeroListMixin } from '@/mixins/JeroListMixin'
import JTable from '../../../components/jero/JTable'
import { filterObj } from '../../../utils/util'
import { askForAdvice } from '../../../common/lang/businessSupport/zh'
export default {
name: 'AskForAdviceList',
computed: {
askForAdvice () {
return askForAdvice
}
},
components: { JTable },
mixins: [JeroListMixin],
data () {
return {
columns: [
// 标准名称/编号
{
title: this.$t('businessSupport.askForAdvice.standardNameNumber'),
width: 200,
dataIndex: 'standardNameNumber',
scopedSlots: { customRender: 'detail' }
},
// 征求意见周期
{
title: this.$t('businessSupport.askForAdvice.consultationCycle'),
width: 200,
dataIndex: 'consultationPeriod'
}
],
dataSource: [],
url: {
list: '/laws/consultation/queryByPage'
}
}
},
methods: {
toDetailPage ({ id }) {
this.$router.push({
path: '/businessSupport/AskForAdviceDetail',
query: { id }
})
},
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
if (param.consultationPeriodList && param.consultationPeriodList.length > 0) {
param.consultationPeriod = param.consultationPeriodList.join(',')
delete param.consultationPeriodList
}
return filterObj(param)
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
</style>
@@ -0,0 +1,42 @@
<template>
<j-modal
:title="$t('view')"
:visible="visible"
:width="1000"
:footer="false"
switchFullscreen
@cancel="handleCancel">
<div class="text-content">{{ content }}</div>
</j-modal>
</template>
<script>
export default {
name: 'TextContentModal',
data () {
return {
visible: false,
content: null
}
},
methods: {
open (text) {
this.content = text
this.visible = true
},
handleCancel () {
this.visible = false
this.content = null
}
}
}
</script>
<style scoped lang="less">
.text-content {
max-height: calc(100vh - 200px - 55px);
overflow: auto;
margin: 0 -24px;
padding: 0 24px;
}
</style>
@@ -0,0 +1,688 @@
<template>
<a-card :bordered="false">
<div class="left-tree-div">
<div class="div-left">
<div>
<a-input-search style="margin-bottom: 8px" :placeholder="$t('nodeQuickLookup')" @change="onLeftChange"
@search="onSearch"/>
<a-tree
:selected-keys="selectedKeys"
:expanded-keys.sync="expandedKeys"
:auto-expand-parent="autoExpandParent"
:defaultExpandAll="true"
:tree-data="gData"
@expand="onExpand"
@rightClick="rightClick"
@select="onSelect"
>
<template #title="{ key: treeKey, title }">
<a-dropdown :trigger="['contextmenu']">
<!-- <span>{{ title }}</span>-->
<span v-if="title.indexOf(searchValue) >= -1 && title.length <= 18" :title="title"
class="expand-title">
{{ title.substr(0, title.indexOf(searchValue)) }}<span
style="color: #f50">{{ searchValue }}</span>{{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
</span>
<span
v-else-if="title.indexOf(searchValue) >= -1 && title.length > 18 && title.indexOf(searchValue)>18"
:title="title">
{{title && title.length > 18?title.slice(0,17)+'...':title}}
</span>
<span
v-else-if="title.indexOf(searchValue) >= -1 && title.length > 18 && title.indexOf(searchValue)<=18"
:title="title">
{{ title.substr(0, title.indexOf(searchValue)) }}<span style="color: #f50">{{ title.indexOf(searchValue)+searchValue.length>18?searchValue.substr(0,18-title.indexOf(searchValue)) : searchValue }}</span>{{ title.indexOf(searchValue)+searchValue.length>18?'...': title.substr(title.indexOf(searchValue) + searchValue.length,18-title.indexOf(searchValue) - searchValue.length)+'...' }}
</span>
<span v-else :title="title">
{{title && title.length > 18?title.slice(0,17)+'...':title}}
</span>
<template #overlay v-if='manager'>
<a-menu>
<a-menu-item key="1" @click="orgAdd">{{$t('treeRight.addFolder')}}</a-menu-item>
<a-menu-item key="4" @click="orgAdds" v-if="notAddChildNode">{{$t('treeRight.addSubFolders')}}</a-menu-item>
<a-menu-item key="2" @click="orgEdit">{{$t('treeRight.editFolder')}}</a-menu-item>
<a-menu-item key="3" @click="orgDelete">{{$t('treeRight.deleteFolders')}}</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</a-tree>
</div>
</div>
<div class="div-right">
<div class="div-right-wrapper">
<div class="right-search-header table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="8" :sm="8">
<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="8" :sm="8">
<a-form-item :label="$t('uploadedBy')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter')+$t('uploadedBy')"
v-model="queryParam.createBy"></a-input>
</a-form-item>
</a-col>
<template v-if="toggleSearchStatus">
<a-col :md="8" :sm="8">
<a-form-item :label="$t('uploadTime')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-range-picker
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style='margin-left: -1px'
v-model="queryParam.time"
:disabled="false"/>
</a-form-item>
</a-col>
</template>
<span style="float: right;overflow: hidden;margin-right: 11px" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a @click="handleToggleSearch">
<span class="icon-open">{{ !toggleSearchStatus ? $t('open') : $t('putAway') }}</span>
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
</a>
<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>
</a-col>
</span>
</a-row>
</a-form>
</div>
<div class="table-operator" style="overflow:hidden;margin-bottom: 20px">
<div style="float: right;margin-bottom: 0px;margin-left: 20px">
<!-- v-has="'externalReport:upload'"-->
<div class="operator-text"
@click="handleuploadFile" v-if='authmanage'>
<a-icon type="cloud-upload"/>
{{ $t('uploadFileBtn') }}
</div>
<div class="operator-text"
v-has="'externalReport:batchDelete'"
@click="handleDel" v-if='authmanage'>
<a-icon type="delete"/>
{{ $t('batchDelete') }}
</div>
</div>
</div>
<div>
<j-table
ref="table"
size="middle"
:can-drag="true"
:loading="loading"
:pagination="ipagination"
rowKey="id"
:scroll="{x: '100%',y:'calc(100vh - 180px)'}"
:data-source="dataSource"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:columns="columns"
@change="handleTableChange"
>
<template v-slot:projectName="{text}" :title="text">
{{ text }}
</template>
<template v-slot:fileName="{text}" :title="text">
{{ text }}
</template>
<!-- v-has="'externalReport:download'"-->
<!-- v-has="'externalReport:edit'"-->
<!-- v-has="'externalReport:delete'"-->
<!-- v-if="authmanage"-->
<!-- <template v-slot:operation="{text, record}">-->
<!-- <a class="text-operation"-->
<!-- @click="download(record)">{{$t('download')}}</a>-->
<!-- <a-divider type="vertical"/>-->
<!-- <a-dropdown v-if="authmanage">-->
<!-- <a class="ant-dropdown-link">-->
<!-- {{ $t('more') }} <a-icon type="down"/>-->
<!-- </a>-->
<!-- <a-menu slot="overlay">-->
<!-- <a-menu-item>-->
<!-- <a class="text-operation"-->
<!-- @click="handleEdit(record)">{{$t('edit')}}</a>-->
<!-- </a-menu-item>-->
<!-- <a-menu-item>-->
<!-- <a class="text-operation"-->
<!-- @click="batchDel(record)">{{$t('delete')}}</a>-->
<!-- </a-menu-item>-->
<!-- </a-menu>-->
<!-- </a-dropdown>-->
<!-- </template>-->
<template v-slot:operation="{text, record}">
<a v-for="(operation, index) in operationList.slice(0, operateMaxNum)" :key="index" class="text-operation"
@click="operationClick(record)">{{operation.text}}</a>
<!-- authmanage &&-->
<a-divider v-if="operationList.length >= operateMaxNum" type="vertical"/>
<a-dropdown v-if="operationList.length >= operateMaxNum">
<a class="ant-dropdown-link">{{ $t('more') }} <a-icon type="down"/></a>
<a-menu slot="overlay">
<a-menu-item v-for="(operation, index) in operationList.slice(operateMaxNum)" :key="index">
<!-- v-if="authmanage"-->
<a class="text-operation" @click="operationClick(record)">{{operation.text}}</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</j-table>
</div>
<!-- 上传文件-->
<addModel ref="addModelRef" @addModelList="addModelList"/>
<!-- 添加节点-->
<add-node-modal ref="addNodeModal" @ok="addNodeOk"></add-node-modal>
</div>
</div>
</div>
</a-card>
</template>
<script>
import JTable from '@/components/jero/JTable'
// 上传文件弹框
import AddModel from './modules/AddModel'
// 添加节点弹框
import AddNodeModal from './modules/AddNodeModal'
import { getAction, postAction, downloadFile, deleteAction } from '@/api/manage'
import { JeroListMixin } from '@/mixins/JeroListMixin'
export default {
name: 'DataCenter',
components: {
JTable,
AddModel,
AddNodeModal
},
mixins: [JeroListMixin],
data () {
return {
operationList: [
{
text: this.$t('download'),
clickEvent: 'download',
has: 'externalReport:download'
},
{
text: this.$t('edit'),
clickEvent: 'handleEdit',
has: 'externalReport:edit'
},
{
text: this.$t('delete'),
clickEvent: 'batchDel',
has: 'externalReport:delete'
}
],
labelCol: { span: 6 },
wrapperCol: { span: 16 },
disabled: false,
manager: false, // 是否有树右键菜单
addSub: true,
dataSource: [
{ id: 1 }
],
expandedKeys: [],
searchValue: '',
autoExpandParent: true,
dataList: [],
gData: [],
loading: false,
attId: '',
data: [],
nodeTreeItem: null, // 右键菜单
tmpStyle: '', // 右键菜单位置
infoId: '',
menuId: '',
itemId: '',
itemVal: {},
columns: [
{
title: this.$t('fileName'),
align: 'left',
ellipsis: true,
dataIndex: 'fileName',
scopedSlots: { customRender: 'fileName' },
width: 270
},
{
title: this.$t('fileDeclaration'),
align: 'left',
ellipsis: true,
dataIndex: 'fileDescription',
scopedSlots: { customRender: 'projectName' },
width: 390
},
{
title: this.$t('uploadedBy'),
align: 'left',
ellipsis: true,
dataIndex: 'createBy',
width: 150
},
{
title: this.$t('uploadTime'),
align: 'left',
ellipsis: true,
dataIndex: 'createTime',
width: 150
},
{
title: this.$t('operation'),
align: 'center',
fixed: 'right',
ellipsis: true,
width: 240,
scopedSlots: { customRender: 'operation' }
}
],
url: {
list: '/extRepo/extRepoData/page',
getSysCategoryTree: '/sys/category/getSysCategoryTree'
},
// upAccept:'.zip', //导入文件类型
selectedKeys: [],
notAddChildNode: false,
authmanage: false,
fullWidth: ''
}
},
mounted () {
this.loadMenuData()
this.generateList(this.gData)
},
methods: {
// 获取左侧菜单的下级
generateList (data) {
for (let i = 0; i < data.length; i++) {
const node = data[i]
const key = node.key
this.dataList.push({ key, title: key })
if (node.children) {
this.generateList(node.children)
}
}
},
// 获取传入的树中最上层的key
getParentKey (key, tree) {
let parentKey
for (let i = 0; i < tree.length; i++) {
const node = tree[i]
if (node.children) {
if (node.children.some(item => item.key === key)) {
parentKey = node.key
} else if (this.getParentKey(key, node.children)) {
parentKey = this.getParentKey(key, node.children)
}
}
}
return parentKey
},
// 树的展开
onExpand (expandedKeys) {
this.expandedKeys = expandedKeys
this.autoExpandParent = false
},
// 左侧搜索框的改变
onLeftChange (e) {
const value = e.target.value
const expandedKeys = this.dataList
.map(item => {
if (item.title.indexOf(value) > -1) {
return this.getParentKey(item.key, this.gData)
}
return null
})
.filter((item, i, self) => item && self.indexOf(item) === i)
Object.assign(this, {
expandedKeys,
searchValue: value,
autoExpandParent: true
})
this.onSearch()
},
// 获取左侧目录数据
loadMenuData () {
// let params = {
// infoId: this.infoId
// }
this.loading = true
getAction(`extRepo/extRepoFolder/list`, {}).then(res => {
if (res.success) {
this.data = res.result.list
this.menuId = this.data[0].key
this.loadData()
this.gData = [...this.data]
Object.assign(this, {
expandedKeys: this.expandedKeys,
autoExpandParent: true
})
}
}).finally(() => {
this.loading = false
})
},
// 鼠标右键
rightClick ({ event, node }) {
this.notAddChildNode = node._props.dataRef.level !== 4
this.manager = node._props.dataRef.manager === true
const x = event.currentTarget.offsetLeft + event.currentTarget.clientWidth
const y = event.currentTarget.offsetTop
console.log(node._props.dataRef)
this.nodeTreeItem = {
pageX: x,
pageY: y,
authManageIdsName: node._props.dataRef.authManageIdsName,
authViewIds: node._props.dataRef.authViewIds,
key: node._props.dataRef.key,
authManageIds: node._props.dataRef.authManageIds,
authViewIdsName: node._props.dataRef.authViewIdsName,
title: node._props.dataRef.title,
folderName: node._props.dataRef.folderName,
orderId: node._props.dataRef.orderId
}
this.nodeItem = JSON.parse(JSON.stringify(this.nodeTreeItem))
this.tmpStyle = {
position: 'absolute',
maxHeight: 40,
textAlign: 'center',
left: `${x + 10 - 0}px`,
top: `${y + 6 - 0}px`,
background: `#FFFFFF`,
zIndex: `2`
}
},
// 用于点击空白处隐藏增删改菜单
clearMenu () {
this.nodeTreeItem = null
},
// 选择树节点
onSelect (selectedKeys) {
this.menuId = selectedKeys[0]
this.selectedKeys = selectedKeys
this.searchQuery()
},
// 树形新增文件夹
orgAdd () {
this.$refs.addNodeModal.menuTitle = this.$t('treeRight.addFolder')
const form = {}
form.supFolder = this.nodeItem.key
form.addSub = false
const params = {}
params.id = this.nodeItem.key
postAction(`extRepo/extRepoFolder/isAllowSiblingFolder`, params).then(res => {
if (res.success) {
this.$refs.addNodeModal.open(false, form)
} else {
this.$message.warning(res.message)
}
})
},
// 树形新增子文件夹
orgAdds () {
this.$refs.addNodeModal.menuTitle = this.$t('treeRight.addSubFolders')
const form = {}
form.supFolder = this.nodeItem.key
form.addSub = true
this.$refs.addNodeModal.open(false, form)
},
// 树形修改
orgEdit () {
this.menuTitle = this.$t('treeRight.editFolder')
const form = {}
form.id = this.nodeItem.key
form.authManageIds = this.nodeItem.authManageIds
form.authViewIds = this.nodeItem.authViewIds
form.authManageIdsName = this.nodeItem.authManageIdsName
form.authViewIdsName = this.nodeItem.authViewIdsName
form.folderName = this.nodeItem.folderName
form.orderId = this.nodeItem.orderId
this.$refs.addNodeModal.open(true, form)
},
// 树形删除
orgDelete () {
this.$confirm({
content: this.$t('treeRight.deleteNode'),
onOk:
async () => {
deleteAction(`extRepo/extRepoFolder/delete`, { id: this.nodeItem.key }).then(res => {
if (res.success) {
this.$message.success(res.message)
this.loadMenuData()
this.searchQuery()
} else {
this.$message.warning(res.message)
}
})
}
})
},
// 添加或编辑节点成功
addNodeOk () {
this.expandedKeys.push(this.nodeItem.id)
this.loadMenuData()
this.searchQuery()
},
// 上传文件弹框成功后的回调
addModelList () {
this.ipagination.current = 1
this.loadData()
},
// 获取列表数据
loadData (item) {
this.queryParam.supFolder = this.menuId
this.queryParam.pageNo = this.ipagination.current
this.queryParam.pageSize = this.ipagination.pageSize
const params = {
...this.queryParam,
...item
}
this.loading = true
getAction(this.url.list, params).then(res => {
if (res.success) {
if (res.result.pageList.current > 1 && res.result.pageList.records.length === 0) {
this.ipagination.current = 1
this.loadData()
return
}
this.dataSource = res.result.pageList.records || []
this.authmanage = res.result.auth_manage
this.ipagination.total = res.result.pageList.total
}
}).finally(() => {
this.loading = false
})
},
// 搜索
searchQuery (item) {
this.ipagination.current = 1
if (this.queryParam.time && this.queryParam.time instanceof Array) {
this.queryParam.time = this.queryParam.time.join(',')
}
this.loadData(item)
},
// 清空
searchReset () {
this.ipagination.current = 1
this.queryParam = {}
this.loadData()
},
// 编辑
handleEdit (item) {
this.$refs.addModelRef.editModel(JSON.parse(JSON.stringify(item)))
},
// 下载
download (item) {
const query = {
id: item.fileKey
}
downloadFile('/sys/common/downLoadFile', item.fileName, query)
},
// 删除
batchDel (val) {
this.$confirm({
content: this.$t('confirmDeletion'),
onOk: () => {
deleteAction('extRepo/extRepoData/delete', { id: val.id }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warning(res.message)
}
})
}
})
},
// 批量删除
handleDel () {
if (this.selectedRowKeys.length > 0) {
this.$confirm({
content: this.$t('confirmBatchDeletion'),
onOk: () => {
const idList = this.selectedRowKeys
deleteAction('extRepo/extRepoData/deleteBatch', { ids: idList.join(',') }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.selectedRowKeys = []
this.loadData()
} else {
this.$message.warning(res.message)
}
})
}
})
} else {
this.$message.warning(this.$t('selectLeastOne'))
}
},
// 选择框
onSelectChange (selectedRowKeys, rows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = rows
},
// 上传文件
handleuploadFile (e) {
if (this.menuId) {
this.$refs.addModelRef.addModel(this.menuId)
} else {
this.$message.warning(this.$t('businessSupp.dataCenter.selectDirectorylocation'))
}
},
onSearch () {
const self = this
const tree = JSON.parse(JSON.stringify(this.data))
this.expandedKeys = []
if (this.searchValue.trim() === '') {
this.gData = JSON.parse(JSON.stringify(this.data))
return
}
if (tree && tree.length > 0) {
tree.forEach((n, i, a) => {
self.searchEach(n, this.searchValue)
})
// 没有叶子节点的根节点也要清理掉
const length = tree.length
for (let i = length - 1; i >= 0; i--) {
const e2 = tree[i]
if (!this.isHasChildren(e2) && e2.title.indexOf(this.searchValue) <= -1) {
tree.splice(i, 1)
this.expandedKeys.push(e2.key)
}
}
this.gData = [...tree]
}
},
searchEach (node, value) {
const depth = this.getTreeDepth(node)
const self = this
for (let i = 0; i < depth - 1; i++) {
let spliceCounter = 0
this.traverseTree(node, n => {
if (self.isHasChildren(n)) {
const children = n.children
const length = children.length
for (let j = length - 1; j >= 0; j--) {
const e3 = children[j]
if (!self.isHasChildren(e3) && e3.title.indexOf(value) <= -1) {
children.splice(j, 1)
spliceCounter++
} else {
this.expandedKeys.push(e3.key)
}
}
}
})
if (spliceCounter === 0) {
break
}
}
},
// 判断树形结构中的一个节点是否具有孩子节点
isHasChildren (node) {
let flag = false
if (node.children && node.children.length > 0) {
flag = true
}
return flag
},
// 通过传入根节点获得树的深度
getTreeDepth (node) {
if (undefined === node || node == null) {
return 0
}
let r = 0
let currentLevelNodes = [node]
while (currentLevelNodes.length > 0) {
r++
let nextLevelNodes = []
for (let i = 0; i < currentLevelNodes.length; i++) {
const e = currentLevelNodes[i]
if (this.isHasChildren(e)) {
nextLevelNodes = nextLevelNodes.concat(e.children)
}
}
currentLevelNodes = nextLevelNodes
}
return r
},
traverseTree (node, callback) {
if (!node) {
return
}
const stack = []
stack.push(node)
let tmpNode
while (stack.length > 0) {
tmpNode = stack.pop()
callback(tmpNode)
if (tmpNode.children && tmpNode.children.length > 0) {
for (let i = tmpNode.children.length - 1; i >= 0; i--) {
stack.push(tmpNode.children[i])
}
}
}
},
// 正则替换小数点
limitNumber (value) {
if (typeof value === 'string') {
return !isNaN(Number(value)) ? value.replace(/\./g, '') : 0
} else if (typeof value === 'number') {
return !isNaN(value) ? String(value).replace(/\./g, '') : 0
} else {
return 0
}
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
</style>
@@ -0,0 +1,183 @@
<template>
<div>
<j-modal
:title="title"
:maskClosable="false"
:width="600"
placement="right"
:closable="true"
@cancel="handleCancel"
:visible="visible"
switchFullscreen
style="height: 100%;overflow: auto;padding-bottom: 53px;">
<a-spin :tip="this.$t('businessSupp.dataCenter.fileUploaded')" :spinning="spinning">
<a-form>
<a-form-model :model="formInline" class="form-add" :rules="rules" ref="ruleForm">
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="required">*</span>
<span class="title-text-text"
:title="$t('fileName')">{{$t('fileName')}}</span>
</div>
<a-form-model-item class="item-model" prop="fileKey">
<a-button type="primary" class="button-text"
@click="clickButtonToUpload('fileKey')">
{{ (formInline.fileKey === 'null' || formInline.fileKey === '' ||
formInline.fileKey == null) ? $t('uploadFile.clickUpload') : $t('uploadFile.viewUploadedFiles')
}}
</a-button>
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="title-text-text" :title="$t('fileDeclaration')">{{$t('fileDeclaration')}}</span>
</div>
<a-form-model-item class="item-model-textarea" prop="fileDescription">
<a-textarea :placeholder="$t('pleaseEnter')+$t('fileDeclaration')"
:maxLength="200"
:rows="4"
v-model="formInline.fileDescription"/>
</a-form-model-item>
</div>
</a-col>
</a-row>
</a-form-model>
</a-form>
</a-spin>
<div class="drawer-bootom-button">
<a-button style="margin-right: 8px" @click="handleCancel">{{$t('cancel')}}</a-button>
<a-button @click="handleSubmit" type="primary">{{$t('submit')}}</a-button>
</div>
</j-modal>
<upload-file ref="uploadFile" @change="uploadFileChange" :return-url="false"></upload-file>
</div>
</template>
<script>
import UploadFile from '@/components/UploadFile'
import { postAction, putAction } from '@/api/manage'
export default {
name: 'AddModel',
components: { UploadFile },
data () {
return {
formInline: {},
spinning: false,
menuId: '',
visible: false,
url: {
add: 'extRepo/extRepoData/add',
edit: 'extRepo/extRepoData/edit'
},
rules: {
fileDescription: [
// { required: true, message: this.$t('pleaseEnter')+this.$t('fileDeclaration'), trigger: 'blur' },
],
fileKey: [
{
required: true,
message: this.$t('fileName') + this.$t('cannotEmpty'),
trigger: 'change'
}
]
},
disabled: false,
title: ''
}
},
methods: {
addModel (menuId) {
this.visible = true
this.title = this.$t('uploadFileBtn')
this.disabled = false
this.menuId = menuId
this.formInline = {}
this.$nextTick(() => {
this.$refs.ruleForm.clearValidate()
})
},
editModel (value) {
this.visible = true
this.title = this.$t('edit')
this.disabled = true
this.$nextTick(() => {
this.formInline = value
this.$refs.ruleForm.clearValidate()
})
},
handleCancel () {
if (this.spinning === true) {
this.visible = true
} else {
this.$refs.ruleForm.clearValidate()
this.visible = false
}
},
handleSubmit () {
if (this.spinning) {
return
}
this.$refs.ruleForm.validate(valid => {
if (valid) {
this.spinning = true
let url = ''
let Action
if (this.formInline.id) {
url = this.url.edit
Action = putAction
} else {
url = this.url.add
Action = postAction
}
this.formInline.supFolder = this.menuId
const query = JSON.parse(JSON.stringify(this.formInline))
Object.keys(query).forEach(res => {
if (query[res] && query[res] instanceof Array) {
query[res] = query[res].join(',')
}
})
Action(url, query).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.visible = false
this.$emit('addModelList')
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.spinning = false
})
}
})
},
// 文件上传改变后的回调
uploadFileChange (data) {
const attIdList = []
if (data && data.length > 0) {
data.map(item => {
attIdList.push(item.id || data.name)
})
}
/** 赋值给当前对应的表单文件 */
this.formInline[this.uploadName] = attIdList.join(',')
this.formInline = { ...this.formInline }
this.$refs.ruleForm.clearValidate(['fileKey'])
},
clickButtonToUpload (item) {
this.$refs.uploadFile.open(this.formInline[item])
this.uploadName = item
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
</style>
@@ -0,0 +1,210 @@
<template>
<j-modal
class="add-menus"
:title="title"
:width="600"
:visible="visible"
switchFullscreen
:confirm-loading="confirmLoading"
@cancel="handleCancelMenuRight"
@ok="hideModalMenuRight"
>
<a-form-model
class="split-click-right-form"
ref="ruleForm"
:model="form"
:rules="rules"
>
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="required">*</span>
<span class="title-text-text"
:title="$t('treeRight.folderName')">{{$t('treeRight.folderName')}}</span>
</div>
<a-form-model-item prop="folderName" style='width: 72%'>
<a-input
v-model="form.folderName"
style='width: 130%'
class="box-input add-input"
maxLength="100"
:placeholder="$t('pleaseEnter')+$t('treeRight.folderName')"/>
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="title-text-text"
:title="$t('treeRight.administrativePrivileges')">{{$t('treeRight.administrativePrivileges')}}</span>
</div>
<a-form-model-item class="itemModel-multi" prop="authManageIdsName">
<a-select
mode="multiple"
v-model="form.authManageIdsName"
:placeholder="$t('pleaseSelect')+$t('treeRight.administrativePrivileges')"
:filter-option="false"
:not-found-content="null"
allowClear
@search="personSearch"
>
<a-select-option v-for="item in personList" :key="item.id" :value="item.id">
{{ item.realname }}
</a-select-option>
<template slot="notFoundContent">
<a-empty></a-empty>
</template>
</a-select>
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="title-text-text"
:title="$t('treeRight.checkPermissions')">{{$t('treeRight.checkPermissions')}}</span>
</div>
<a-form-model-item class="itemModel-multi" prop="authViewIdsName">
<a-select
mode="multiple"
v-model="form.authViewIds"
:placeholder="$t('pleaseSelect')+$t('treeRight.administrativePrivileges')"
:filter-option="false"
:not-found-content="null"
allowClear
@search="personSearch"
>
<a-select-option v-for="item in personList" :key="item.id" :value="item.id">
{{ item.realname }}
</a-select-option>
<template slot="notFoundContent">
<a-empty></a-empty>
</template>
</a-select>
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="24">
<div class="box-title-text">
<div class="title-text">
<span class="Required">*</span>
<span class="title-text-text"
:title="$t('treeRight.folderOrder')">{{$t('treeRight.folderOrder')}}</span>
</div>
<a-form-model-item class="itemModel" prop="orderId">
<a-input-number v-model="form.orderId" :min="1" :max="9999" class="box-input add-input"
:placeholder="$t('pleaseEnter')+$t('treeRight.folderOrder')" :formatter="limitNumber"
:parser="limitNumber"/>
</a-form-model-item>
</div>
</a-col>
</a-row>
</a-form-model>
</j-modal>
</template>
<script>
import { getUserList } from '@/api/api'
import { postAction, putAction } from '@/api/manage'
export default {
name: 'AddNodeModal',
data () {
return {
title: this.$t('add'),
visible: false,
confirmLoading: false,
form: {},
rules: {
folderName: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('treeRight.folderName'), trigger: 'blur' }
],
// authManageIdsName: [
// { required: true, message: this.$t('pleaseSelect') + this.$t('treeRight.administrativePrivileges'), trigger: 'change' },
// ],
// authViewIdsName: [
// { required: true, message: this.$t('pleaseSelect') + this.$t('treeRight.checkPermissions'), trigger: 'change' },
// ],
orderId: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('treeRight.folderOrder'), trigger: 'blur' }
]
},
personList: [],
isEdit: false
}
},
methods: {
open (isEdit, form) {
this.visible = true
this.isEdit = true
this.form = Object.assign({}, form)
},
personSearch (value) {
getUserList({ pageNo: 1, pageSize: 20, realname: '*' + value + '*' }).then(res => {
if (res.success) {
this.personList = res.result.records || []
}
})
},
// 取消文件夹的新增或编辑
handleCancelMenuRight () {
this.visible = false
this.$refs.ruleForm.clearValidate()
},
// 增加文件夹确定
hideModalMenuRight () {
if (this.confirmLoading) {
return
}
if (!this.isEdit) {
const params = {
...this.form
}
this.$refs.ruleForm.validate(valid => {
if (valid) {
this.confirmLoading = true
postAction(`extRepo/extRepoFolder/add`, params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.form = {}
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
this.visible = false
})
}
})
} else {
const params = {
...this.form
}
putAction(`extRepo/extRepoFolder/edit`, params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.form = {}
this.loadMenuData()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
this.visible = false
})
}
},
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,289 @@
<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 :span="6">
<a-form-item :label="$t('businessSupport.questionAnswer.classify')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-dict-select-tag
:placeholder="$t('pleaseSelect')+$t('businessSupport.questionAnswer.classify')"
dict-code="problem_library_type"
v-model="queryParam.type">
</j-dict-select-tag>
</a-form-item>
</a-col>
<!-- 标准号 -->
<a-col :span="6">
<a-form-item :label="$t('standardNumber')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-input :placeholder="$t('pleaseEnter')+$t('standardNumber')" v-model="queryParam.standardNumber"></j-input>
</a-form-item>
</a-col>
<!-- 标准名称 -->
<a-col :span="6">
<a-form-item :label="$t('standardName')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-input :placeholder="$t('pleaseEnter')+$t('standardName')" v-model="queryParam.standardName"></j-input>
</a-form-item>
</a-col>
<template v-if="toggleSearchStatus">
<!-- 标题 -->
<a-col :span="6">
<a-form-item :label="$t('title')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-input :placeholder="$t('pleaseEnter')+$t('title')" v-model="queryParam.title"></j-input>
</a-form-item>
</a-col>
</template>
<div style="float: right;overflow: hidden;" class="table-page-search-submitButtons">
<a @click="handleToggleSearch">
{{ toggleSearchStatus ? $t('putAway') : $t('open') }}
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
</a>
<a-button type="primary" @click="searchQuery" icon="search" style="margin-left: 8px" v-has="'businessSupport:questionAnswer:search'">{{ $t('query') }}</a-button>
<a-button type="primary" ghost @click="searchReset" icon="reload" style="margin-left: 8px">{{ $t('reset') }}</a-button>
</div>
</a-row>
</a-form>
</div>
<!-- 操作区域 -->
<div class="table-operator">
<!-- 提问 -->
<a-button icon="plus" type="primary" v-has="'businessSupport:questionAnswer:quiz'"
@click="handleQuiz">
{{ $t('businessSupport.questionAnswer.quiz') }}
</a-button>
</div>
<div>
<j-table
:can-drag="true"
:scroll="{x: '100%', y: yScrollHeight}"
ref="table"
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<!-- 解决columns中dataIndex是title的时候控制台报错的问题 -->
<template v-slot:titleSlot="{record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ record.title || record.title === 0 ? record.title : global.emptyLine }}</template>
<div class="table-text">{{ record.title || record.title === 0 ? record.title : global.emptyLine }}</div>
</a-tooltip>
</template>
<!-- 附件 -->
<template v-slot:attach="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<a v-if="text" class="link-a" @click="handleAttachClick(record)">{{ text }}</a>
<span v-else>{{ global.emptyLine }}</span>
</a-tooltip>
</template>
<!-- 操作栏 -->
<div slot="action" slot-scope="{record}" class="action-span-cell">
<!-- 是自己的提问 -->
<template v-if="record.userId === userInfo.id">
<a @click="handleDetail(record)"
class="table-ope-btn"
v-has="'businessSupport:questionAnswer:detail'">
{{ $t('view') }}
</a>
<a-divider type="vertical" />
<a @click="handleDelete(record.id)"
class="table-ope-btn"
v-has="'businessSupport:questionAnswer:delete'">
{{ $t('delete') }}
</a>
</template>
<!-- 是别人的提问 -->
<template v-else>
<a @click="handleAnswer(record)"
class="table-ope-btn"
v-has="'businessSupport:questionAnswer:answer'">
{{ $t('businessSupport.questionAnswer.answer') }}
</a>
</template>
</div>
</j-table>
</div>
<quiz-modal ref="quizModal" @ok="modalFormOk"></quiz-modal>
</a-card>
</template>
<script>
import { JeroListMixin } from '@/mixins/JeroListMixin'
import JTable from '@/components/jero/JTable'
import Vue from 'vue'
import { ACCESS_TOKEN, USER_INFO } from '@/store/mutation-types'
import { previewPdf } from '@/utils/previewPdf'
import { getFileAccessHttpUrl, downloadFile } from '@/api/manage'
import QuizModal from './modules/QuizModal'
import { kkFilePreview } from '@/utils/kkFilePreview'
const FILE_TYPE_IMGS = ['jpg', 'jpeg', 'png', 'raw']
const FILE_TYPE_PDF = 'pdf'
// 支持预览的文件后缀
const CAN_PREVIEW_FILE_SUFFIX = ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx']
export default {
name: 'QuestionAnswerList',
mixins: [JeroListMixin],
components: { QuizModal, JTable },
data () {
return {
/* 排序参数 */
isorter: {
column: 'quizTime',
order: 'desc'
},
labelCol: {
span: 4
},
wrapperCol: {
span: 14
},
columns: [
{ // 分类
title: this.$t('businessSupport.questionAnswer.classify'),
align: 'center',
width: 180,
dataIndex: 'type_dictText',
scopedSlots: { customRender: 'text' }
},
{ // 标准编号
title: this.$t('standardNumber'),
align: 'center',
width: 180,
dataIndex: 'standardNumber',
scopedSlots: { customRender: 'text' }
},
{ // 标准名称
title: this.$t('standardName'),
align: 'center',
width: 180,
dataIndex: 'standardName',
scopedSlots: { customRender: 'text' }
},
{ // 标题
title: this.$t('title'),
align: 'center',
width: 180,
scopedSlots: { customRender: 'titleSlot' }
},
{ // 项目
title: this.$t('project'),
align: 'center',
width: 180,
dataIndex: 'project_dictText',
scopedSlots: { customRender: 'text' }
},
{ // 问题描述
title: this.$t('businessSupport.questionAnswer.questionDesc'),
align: 'center',
width: 180,
dataIndex: 'problemDescription',
scopedSlots: { customRender: 'text' }
},
{ // 提问时间
title: this.$t('businessSupport.questionAnswer.quizTime'),
align: 'center',
width: 180,
dataIndex: 'quizTime',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('operation'),
scopedSlots: { customRender: 'action' },
align: 'center',
fixed: 'right',
width: 200
}
],
url: {
list: '/laws/library/lawsProblemLibrary/page',
delete: '/laws/library/lawsProblemLibrary/deleteProblem'
},
userInfo: {}
}
},
mounted () {
this.userInfo = Vue.ls.get(USER_INFO)
},
methods: {
// 提问
handleQuiz () {
this.$refs.quizModal.title = this.$t('businessSupport.questionAnswer.quiz')
this.$refs.quizModal.open()
},
// 点击相关材料
handleAttachClick (record) {
// 截取文件后缀名
const fileSuffix = record.declareFileName ? record.declareFileName.split('.')[record.declareFileName.split('.').length - 1] : ''
const fileFullUrl = `${window._CONFIG.domianWebSocketURL}/sys/common/view/${record.declareFile}?at=${Vue.ls.get(ACCESS_TOKEN)}&fullfilename=${record.declareFileName}`
const canPreview = CAN_PREVIEW_FILE_SUFFIX.some(tt => fileSuffix === tt)
// 判断是否为可预览格式的文件
if (!canPreview) {
this.$message.loading(this.$t('uploadFile.cannotPreview')).then(() => {
this.handleDownload(record.declareFile, record.declareFileName)
})
return
}
// 图片预览,使用自己添加的组件
if (FILE_TYPE_IMGS.includes(fileSuffix.toLowerCase())) {
this.imageUrl = getFileAccessHttpUrl(record.declareFile)
// 获取viewer实例
const viewer = this.$el.querySelector('.image').$viewer
// 调用show方法进行显示预览图
viewer.show()
// this.$refs.imagePreviewModal.open(file)
return
}
// pdf预览
if (FILE_TYPE_PDF.includes(fileSuffix.toLowerCase())) {
const url = previewPdf(record.declareFile)
window.open(url)
return
}
// 其余可预览文件仍使用KKFile进行预览
kkFilePreview(fileFullUrl)
},
handleDownload (id, name) {
// 下载文件
downloadFile(`/sys/common/download/${id}`, name)
},
// 查看
handleDetail (record) {
this.$router.push({
path: '/businessSupport/questionDetail',
query: {
id: record.id,
canAnswer: 0
}
})
},
// 回答
handleAnswer (record) {
this.$router.push({
path: '/businessSupport/questionDetail',
query: {
id: record.id,
canAnswer: 1
}
})
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
/deep/ .ant-form-item-label{
min-width: 70px !important;
}
</style>
@@ -0,0 +1,278 @@
<template>
<j-modal
:title="title"
:maskClosable="true"
:width="800"
:closable="true"
switchFullscreen
@cancel="handleCancel"
@ok="handleOk"
:visible="visible">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-row :gutter="24">
<!-- 分类 -->
<a-col :span="12">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('businessSupport.questionAnswer.classify')">
<a-select :placeholder="$t('pleaseSelect') + $t('businessSupport.questionAnswer.classify')"
allowClear
@change="typeChange"
v-decorator.trim="[ 'type', validatorRules.type]">
<a-select-option :value="null" :key="-1">请选择</a-select-option>
<a-select-option value="1">国内标准</a-select-option>
<a-select-option value="2">海外标准</a-select-option>
<a-select-option value="3">企业标准</a-select-option>
<a-select-option value="4">其他问题</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 标准编号 -->
<a-col :span="12">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('standardNumber')">
<standard-selection
v-decorator.trim="[ 'standardNumber', validatorRules.standardNumber]"
:placeholder="$t('pleaseSelect') + $t('standardNumber')"
:source="['1', '2', '3'].includes(form.getFieldValue('type')) ? form.getFieldValue('type') : undefined"
:disabledSourceSearch="['1', '2', '3'].includes(form.getFieldValue('type'))"
:selectOnly="true"
type="radio"
@nameChange="standardNameChange"
/>
</a-form-item>
</a-col>
<!-- 标准名称 -->
<a-col :span="12">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('standardName')">
<a-input disabled :placeholder="$t('pleaseEnter') + $t('standardName')"
v-decorator.trim="[ 'standardName', validatorRules.standardName]"/>
</a-form-item>
</a-col>
<!-- 标题 -->
<a-col :span="12">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('title')">
<a-input v-decorator.trim="[ 'title', validatorRules.title]"
:maxLength="50"
:placeholder="$t('pleaseEnter') + $t('title')"/>
</a-form-item>
</a-col>
<!-- 项目 -->
<a-col :span="12">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('project')">
<a-select :placeholder="$t('pleaseSelect') + $t('project')"
allowClear
show-search
:filter-option="filterOption"
v-decorator="[ 'project', validatorRules.project]">
<a-select-option :value="undefined" :key="-1">请选择</a-select-option>
<a-select-option v-for="item in projectList" :value="item.id" :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 :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('businessSupport.questionAnswer.quizTime')">
<a-date-picker
style="width: 100%"
v-decorator.trim="[ 'quizTime', validatorRules.quizTime]"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
showTime
></a-date-picker>
</a-form-item>
</a-col>
<!-- 问题描述 -->
<a-col :span="24">
<a-form-item :labelCol="longLabelCol" :wrapperCol="longWrapperCol" :label="$t('businessSupport.questionAnswer.questionDesc')">
<a-textarea
v-decorator="[ 'problemDescription', validatorRules.problemDescription]"
:placeholder="$t('pleaseEnter')+$t('businessSupport.questionAnswer.questionDesc')"
:maxLength="500"
:rows="4" />
<j-upload v-decorator.trim="[ 'file', validatorRules.file]"
returnId
multiple
isDownload>
</j-upload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</j-modal>
</template>
<script>
import { postAction } from '@/api/manage'
import { getCarTypeProjectList } from '@/api/projectLibraryApi.js'
// 双向绑定的标准选择器
import StandardSelection from '@/components/selection/StandardSelection'
import pick from 'lodash.pick'
import moment from 'moment'
export default {
name: 'QuizModal',
components: { StandardSelection },
data () {
return {
title: '',
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 }
},
longLabelCol: {
xs: { span: 24 },
sm: { span: 3 }
},
longWrapperCol: {
xs: { span: 24 },
sm: { span: 21 }
},
validatorRules: {
type: {
rules: [
{ required: true, message: this.$t('pleaseSelect') + this.$t('businessSupport.questionAnswer.classify') }
],
validateTrigger: 'change'
},
standardNumber: {
rules: [
{ required: true, message: this.$t('pleaseSelect') + this.$t('standardNumber') }
],
validateTrigger: 'change'
},
standardName: {
rules: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('standardName') }
],
validateTrigger: 'blur'
},
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'
},
quizTime: {
rules: [
{ required: false, message: this.$t('pleaseSelect') + this.$t('businessSupport.questionAnswer.quizTime') }
],
validateTrigger: 'change'
},
problemDescription: {
rules: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('businessSupport.questionAnswer.questionDesc') }
],
validateTrigger: 'blur'
},
file: {
rules: [
{ required: false, message: this.$t('pleaseSelect') + this.$t('businessSupport.questionAnswer.attach') }
],
validateTrigger: 'change'
}
},
url: {
quiz: '/laws/library/lawsProblemLibrary/addProblem'
},
projectList: [] // 项目下拉框数据
}
},
created () {
this.getCarTypeProjectList()
},
methods: {
open () {
this.visible = true
this.form.resetFields()
const param = {}
param.quizTime = moment().format('YYYY-MM-DD HH:mm:ss')
this.$nextTick(() => {
this.form.setFieldsValue(pick(param, 'quizTime'))
})
},
// 获取项目下拉框数据
getCarTypeProjectList () {
getCarTypeProjectList({ column: 'createTime', order: 'desc' }).then(res => {
if (res.success) {
this.projectList = res.result
} else {
this.projectList = []
}
})
},
// 分类改变
typeChange (value) {
// 清空标准,否则分类可以和标准类型不一致
this.form.resetFields(['standardNumber', 'standardName'])
if (value) {
if (value === '4') {
// 是其他问题,标准编号和标准名称不必填
this.validatorRules.standardNumber.rules[0].required = false
this.validatorRules.standardName.rules[0].required = false
} else {
// 标准编号和标准名称必填
this.validatorRules.standardNumber.rules[0].required = true
this.validatorRules.standardName.rules[0].required = true
}
}
},
// 标准选择名称改变的回调
standardNameChange (value) {
const param = { standardName: value }
this.$nextTick(() => {
this.form.setFieldsValue(pick(param, 'standardName'))
})
},
handleCancel () {
this.close()
},
handleOk () {
if (this.confirmLoading) return
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
const param = Object.assign({}, values)
postAction(this.url.quiz, param).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
})
}
})
},
close () {
this.visible = false
},
filterOption (input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,479 @@
<template>
<internal-detail-page :title="pageTitle" :loading="loading">
<div class="detail-page-title">{{ model.title }}</div>
<div class="detail-page-second-title">
{{ $t('businessSupport.questionAnswer.poster') + '' + (model.orgCode_dictText || '') + ' ' + (model.userId_dictText || '') }}
</div>
<div class="detail-page-part">
<div class="detail-page-part-form">
<!-- 标准号/标准名称 -->
<div class="detail-page-part-form-item-large">
<label>{{ $t('standardNumOrName') }}</label>
<span class="link" @click="clickStandard">{{ model.standardNumber && model.standardName ? model.standardNumber + ' ' + model.standardName : global.emptyLine }}</span>
</div>
<!-- 项目 -->
<div class="detail-page-part-form-item-large">
<label>{{ $t('project') }}</label>
<span>{{ model.project_dictText || global.emptyLine }}</span>
</div>
<!-- 附件 -->
<div class="detail-page-part-form-item-large-file">
<label>{{ $t('businessSupport.questionAnswer.attach') }}</label>
<template v-if="fileList && fileList.length > 0">
<div class="file-box">
<div class="file-list-file" v-for="file in fileList" :key="file.id">
<div class="file-list-file-info">
<a-icon type="link" />
<div class="file-list-file-name" @click="handlePreview(file)">{{ file.fileName }}</div>
</div>
<!-- 下载-->
<a-button type="link" icon="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>
</div>
</template>
<span v-else>{{ global.emptyLine }}</span>
</div>
</div>
</div>
<!-- 问题描述部分 -->
<div class="question-desc-wrapper">
<p class="question-desc">{{ model.problemDescription }}</p>
<p class="right-bottom-p">
<span class="time-span">{{ model.quizTime }}</span>
<span class="right-bottom-p-span">{{ answerArr.length + $t('businessSupport.questionAnswer.answerNum')}}</span>
</p>
</div>
<!-- 历史回答数据 -->
<template v-if="answerArr && answerArr.length > 0">
<div v-for="(item, index) in answerArr" :key="index" class="answer-form-wrapper">
<div class="answer-form-wrapper-title">
<a-avatar shape="square" :size="28" :src="getAvatarView(item.avatar)" icon="user"/>
<p class="user-name">{{ item.departName || '' }} {{ item.name }}</p>
<p v-if="item.isTop" class="top-p">{{ $t('businessSupport.questionAnswer.top') }}</p>
</div>
<div class="answer-form-desc-div">{{ item.answerDescription }}</div>
<p class="operate-bottom-p">
<span>{{ item.createTime }}</span>
<!-- 置顶评论的操作按钮 -->
<template v-if="item.isTop">
<!-- 取消置顶 -->
<a class="operate-bottom-p-a" @click="setOrCancelTop(item.id)" v-has="'quiz:detail:topOrCancel'">{{ $t('businessSupport.questionAnswer.cancelTop') }}</a>
<!-- 删除 : 发帖人评论人有置顶权限的用户可以删除 ?? -->
<!--<a v-if="userInfo.id === model.userId || userInfo.id === item.userId || isHasPermission('quiz:detail:topOrCancel')" v-has="'quiz:detail:deleteAnswer'" class="operate-bottom-p-a" @click="deleteAnswer(item.id)">{{ $t('delete') }}</a>-->
</template>
<!-- 非置顶评论 -->
<template v-else>
<!-- 设置为置顶 -->
<a class="operate-bottom-p-a" @click="setOrCancelTop(item.id)" v-has="'quiz:detail:topOrCancel'">{{ $t('businessSupport.questionAnswer.setTop') }}</a>
<!-- 删除 : 发帖人评论人有置顶权限的用户可以删除,置顶的评论不允许删除取消置顶后允许删除 -->
<a v-if="userInfo.id === model.userId || userInfo.id === item.userId || isHasPermission('quiz:detail:topOrCancel')" v-has="'quiz:detail:deleteAnswer'" class="operate-bottom-p-a" @click="deleteAnswer(item.id)">{{ $t('delete') }}</a>
</template>
</p>
</div>
</template>
<!-- 回答区域 -->
<div v-if="canAnswer === 1" class="answer-form-wrapper">
<div class="answer-form-wrapper-title">
<a-avatar shape="square" :size="28" :src="getAvatarView(currentUser.avatar)" icon="user"/>
<p class="user-name">{{ currentUser.departIds_dicText || '' }} {{ currentUser.realname }}({{ currentUser.username }})</p>
<p class="answer_question">{{ $t('businessSupport.questionAnswer.answerQuestion') }}</p>
</div>
<a-textarea v-model="answerDesc" :autoSize="{minRows: 4}" :maxLength="2000"></a-textarea>
<p class="answer-desc-num">{{ answerDesc.length }}/2000{{ $t('businessSupport.questionAnswer.word') }}</p>
<a-button class="submit-btn" type="primary" @click="submit" v-has="'quiz:detail:answerSubmit'">{{ $t('submit') }}</a-button>
</div>
<!-- 图片预览容器 -->
<div id="images">
<div class="image" v-viewer="{movable: false}">
<img v-show="image" :src="imageUrl">
</div>
</div>
</internal-detail-page>
</template>
<script>
import { USER_INFO, ACCESS_TOKEN } from '@/store/mutation-types'
import Vue from 'vue'
import { getFileAccessHttpUrl, downloadFile } from '@/api/manage'
import { getQuizById, answerQuiz, setOrCancelTop, deleteAnswer } from '@/api/businessSupport'
import { getFileInfo } from '@/api/api'
import { previewPdf } from '@/utils/previewPdf'
import InternalDetailPage from '@/components/InternalDetailPage'
import { kkFilePreview } from '@/utils/kkFilePreview'
import { isHasPermission } from '@/utils/hasPermission'
// 支持预览的文件后缀
const CAN_PREVIEW_FILE_SUFFIX = ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx']
const FILE_TYPE_IMGS = ['jpg', 'jpeg', 'png', 'raw']
const FILE_TYPE_PDF = 'pdf'
const Base64 = require('js-base64').Base64
export default {
name: 'AnswerPage',
components: { InternalDetailPage },
data () {
return {
loading: false,
pageTitle: '',
model: {},
answerArr: [],
fileList: [],
currentUser: {
avatar: '',
realname: '',
orgCodeTxt: ''
},
answerDesc: '',
canAnswer: false,
userInfo: {},
image: false,
imageUrl: ''
}
},
mounted () {
this.initData(this.$route.query.id)
const userInfo = Vue.ls.get(USER_INFO)
this.userInfo = userInfo
this.currentUser = Object.assign({}, userInfo)
this.canAnswer = Number(this.$route.query.canAnswer)
if (this.canAnswer === 1) {
this.pageTitle = this.$t('businessSupport.questionAnswer.answerQuestionTitle')
} else {
this.pageTitle = this.$t('businessSupport.questionAnswer.questionDetail')
}
},
methods: {
isHasPermission,
// 初始化获取数据信息
initData (id) {
this.loading = true
getQuizById({ id: id }).then(res => {
if (res.success) {
this.model = Object.assign({}, res.result)
if (this.model.file) {
const fileList = this.model.file.split(',')
const fileInfoList = []
fileList.forEach(async id => {
const fileInfo = await this.getFileInfo(id)
if (fileInfo) {
fileInfoList.push(fileInfo)
}
})
this.fileList = fileInfoList
}
this.answerArr = this.model.answerList
}
}).finally(() => {
this.loading = false
})
},
// 获取头像
getAvatarView (avatar) {
return getFileAccessHttpUrl(avatar)
},
getFileInfo (fileId) {
return new Promise(resolve => {
let fileInfo
getFileInfo({ id: fileId }).then(res => {
if (res.success) {
fileInfo = res.result
}
}).finally(() => {
resolve(fileInfo)
})
})
},
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}`
// 图片预览,使用自己添加的组件
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)
console.log(url)
window.open(url)
return
}
// 其余可预览文件仍使用KKFile进行预览
kkFilePreview(fileFullUrl)
},
handleDownload (file) {
// 下载文件
downloadFile(`/laws/standard/common/downloadWithWaterMark/${file.id}`, file.fileName)
},
// 点击标准跳转详情
clickStandard () {
let path = ''
// 需要先判断是哪种标准
if (this.model.type === '1') {
path = '/standardRegulationLibrary/DomesticStandardDetail'
} else if (this.model.type === '2') {
path = '/standardRegulationLibrary/OverseasStandardDetail'
} else if (this.model.type === '3') {
path = '/enterpriseStandardLibrary/enterpriseStandardDetail'
}
this.$openPageNewSheet({
path: path,
query: {
id: this.model.standardId
}
})
},
submit () {
if (!this.answerDesc) {
this.$message.warning(this.$t('businessSupport.questionAnswer.pleaseEnterAnswerDesc'))
return
}
const param = {}
param.problemId = this.model.id
param.answerDescription = this.answerDesc
answerQuiz(param).then(res => {
if (res.success) {
this.$message.success(res.message)
this.initData(this.model.id)
this.answerDesc = ''
} else {
this.$message.warning(res.message)
}
})
},
// 设置或取消置顶
setOrCancelTop (answerId) {
setOrCancelTop({ id: answerId }).then(res => {
if (res.success) {
this.$message.success(res.message)
this.initData(this.model.id)
} else {
this.$message.warning(res.message)
}
})
},
// 删除回答
deleteAnswer (answerId) {
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
deleteAnswer({ id: answerId }).then(res => {
if (res.success) {
this.$message.success(res.message)
this.initData(this.model.id)
} else {
this.$message.warning(res.message)
}
})
}
})
}
}
}
</script>
<style scoped lang="less">
// 二级标题
.detail-page-second-title {
font-size: 16px;
text-align: center;
font-weight: 550;
margin-bottom: 20px;
}
.detail-page-part-form-item-large {
width: 100%;
display: flex;
margin-bottom: 16px;
label {
width: 10em;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
font-weight: 400;
color: #86909C;
}
span {
white-space: pre-wrap;
word-break: break-all;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
color: #1D2129;
}
.link {
color: @primary-color;
cursor: pointer;
}
}
.detail-page-part-form-item-large-file {
width: 100%;
display: flex;
label {
width: 10em;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
font-weight: 400;
color: #86909C;
}
a {
white-space: pre-wrap;
word-break: break-all;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
}
}
// 问题描述部分
.question-desc-wrapper {
border-radius: 8px;
border: 1px solid #E5E6EB;
margin-bottom: 20px;
padding: 20px;
.question-desc {
font-size: 16px;
}
// 右下角的时间和按钮区域
.right-bottom-p {
height: 20px;
text-align: right;
margin-bottom: 0;
.time-span {
color: #86909C;
}
.right-bottom-p-span {
margin-left: 8px;
}
.right-bottom-p-a {
margin-left: 8px;
}
}
}
// 标准信息-附件的文件列表
.file-box {
flex: 1;
width: 0;
}
.file-list {
&-file {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
.file-btn {
padding-right: 0 !important;
}
}
&-file:last-child {
margin-bottom: 0;
}
&-file-info {
display: flex;
align-items: center;
color: @primary-color;
cursor: pointer;
flex: 1;
width: 0;
}
&-file-info > .anticon {
margin-right: 8px;
}
&-file-name {
white-space: nowrap;
overflow: hidden;
flex: 1;
width: 0;
text-overflow: ellipsis;
}
&-file-operate {
.ant-btn > .anticon + span, .ant-btn > .iconfont + span {
margin-left: 10px;
}
.ant-btn:first-child {
margin-left: 15px;
}
}
}
.answer-form-wrapper {
.answer-form-wrapper-title {
display: flex;
.user-name {
font-weight: 560;
margin: 0 10px;
font-size: 16px;
}
.answer_question {
font-size: 16px;
color: #86909C;
}
.top-p {
color: @primary-color;
margin-bottom: 0;
}
}
.answer-form-desc-div {
border-radius: 8px;
border: 1px solid #E5E6EB;
padding: 20px;
margin-top: 5px;
}
.answer-desc-num {
text-align: right;
margin-top: 5px;
margin-bottom: 0;
}
.submit-btn {
margin-top: 20px;
}
// 右下角的时间和按钮区域
.operate-bottom-p {
height: 20px;
text-align: right;
margin: 5px 0 10px 0;
.time-span {
color: #86909C;
}
.operate-bottom-p-span {
margin-left: 8px;
}
.operate-bottom-p-a {
margin-left: 8px;
}
}
}
</style>
@@ -0,0 +1,357 @@
<template>
<internal-detail-page custom-icon
:title="$t('businessSupport.standardizationActivity.currentNode')"
:sub-title="currentNodeName"
sub-title-tooltip
:loading="loading"
:content-padding="0">
<template v-slot:customIcon>
<i class="iconfont icon-nav_apartment page-icon" />
</template>
<template v-slot:titleRightCustom>
<!--新增-->
<a-button type="primary" ghost icon="plus" @click="handleAdd" v-has="'standardActivity:add'">{{
$t('newlyAdded')
}}
</a-button>
<!--编辑-->
<a-button type="primary" ghost icon="edit" @click="handleEdit" v-has="'standardActivity:edit'">{{ $t('edit') }}</a-button>
<!--查看-->
<a-button type="primary" ghost icon="eye" @click="handleDetail" v-has="'standardActivity:view'">{{ $t('view') }}</a-button>
<!--会议统计列表-->
<a-button type="primary" ghost icon="unordered-list" @click="handleStatistical" v-has="'standardActivity:statistical'">{{
$t('businessSupport.standardizationActivity.conferenceStatisticsList')
}}
</a-button>
</template>
<div class="table-page-search-wrapper search-box" :class="{'search-box-shadow': showSearch}">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :span="14">
<!-- 节点名称-->
<a-form-item :label="$t('businessSupport.standardizationActivity.nodeName')">
<a-input v-model="nodeName"
:placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.nodeName')"
@input="handleSearch" />
</a-form-item>
</a-col>
<a-col :span="10">
<div style="float: right;overflow: hidden;margin-right: 11px" class="table-page-search-submitButtons">
<a-button class="box-button"
style="margin-left: 8px"
type="primary"
@click="searchQuery"
icon="search"
v-has="'standardActivity:search'">{{
$t('query')
}}
</a-button>
<a-button class="box-button" icon="reload" @click="searchReset">{{ $t('reset') }}</a-button>
</div>
</a-col>
</a-row>
</a-form>
<template>
<!--点击查询后展示的列表-->
<div class="search-node-list" :class="{'hide-search': !showSearch}">
<div class="search-node-item" v-for="node in nodeNameList" @click="handleSearchNode(node)">
<span v-if="hasSearchVal(node.name)">{{
beforeSearchVal(node.name)
}}<span class="highlight-text">{{ searchValInText(node.name) }}</span>{{ afterSearchVal(node.name) }}</span>
<span v-else>{{ node.name }}</span>
</div>
</div>
<!--遮罩-->
<div class="search-overlay" v-show="showSearch" @click="hideSearch"></div>
</template>
</div>
<!--思维导图部分-->
<mind-map ref="mindMap" dom-id="mountNode" :map-data="data" map-data-key-field="name" @select="handleSelectNode" />
<!--新增/编辑-->
<standardization-activity-drawer ref="modalForm" @ok="modalFormOk" />
<!--统计列表-->
<statistical-list-drawer ref="statisticalDrawer" />
</internal-detail-page>
</template>
<script>
import MindMap from '../../../components/MindMap.vue'
import InternalDetailPage from '../../../components/InternalDetailPage'
import { queryTreeList } from '../../../api/businessSupport'
import StandardizationActivityDrawer from './modules/StandardizationActivityDrawer'
import StatisticalListDrawer from './modules/StatisticalListDrawer'
export default {
name: 'StandardizationActivityPage',
components: { InternalDetailPage, MindMap, StandardizationActivityDrawer, StatisticalListDrawer },
data () {
return {
nodeName: '',
nodeNameList: [], // 查询的下拉数据
defaultNodeNameList: [], // 查询的下拉数据
data: {},
currentNodeName: '',
showSearch: false,
loading: false,
selectedNodeId: null, // 选中节点的信息
selectedNode: {}
}
},
created () {
this.loadData()
},
methods: {
/**
* 获取数据
*/
loadData () {
this.loading = true
queryTreeList().then(res => {
if (res.success) {
this.data = Object.assign({}, res.result)
this.treeToArr([this.data], null, this.defaultNodeNameList)
}else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleSearch () {
if (!this.nodeName) {
this.nodeNameList = []
return
}
this.nodeNameList = this.defaultNodeNameList.filter(tt => tt.name.toLowerCase().indexOf(this.nodeName.toLowerCase()) !== -1)
},
searchReset () {
this.nodeName = null
this.nodeNameList = []
this.currentNodeName = null
this.selectedNode = {}
this.selectedNodeId = null
this.$refs.mindMap.searchNode()
this.hideSearch()
},
searchQuery () {
this.showSearch = true
},
hideSearch () {
this.showSearch = false
},
treeToArr (data, pid = null, res) {
data.forEach(item => {
res.push(item)
if (item.children && item.children.length !== 0) {
this.treeToArr(item.children, item.id, res)
}
})
return res
},
/**
* 是否包含搜索的文本
* @param text
* @returns {boolean}
*/
hasSearchVal (text) {
const filterText = text || ''
const searchVal = this.nodeName || ''
return text && filterText.toLowerCase().indexOf(searchVal.toLowerCase()) !== -1
},
/**
* 查询关键字之前的
* @param text
* @returns {string}
*/
beforeSearchVal (text) {
const filterText = text || ''
const searchVal = this.nodeName || ''
const index = filterText.toLowerCase().indexOf(searchVal.toLowerCase())
return filterText.substring(0, index)
},
/**
* 为了保留大小写,需要吧查询的内容也特殊处理一下
* @param text
* @returns {string}
*/
searchValInText (text) {
const filterText = text || ''
const searchVal = this.nodeName || ''
const index = filterText.toLowerCase().indexOf(searchVal.toLowerCase())
return filterText.substring(index, index + searchVal.length)
},
/**
* 输入内容后面的部分
* @param text
* @returns {string}
*/
afterSearchVal (text) {
const filterText = text || ''
const searchVal = this.nodeName || ''
const index = filterText.toLowerCase().indexOf(searchVal.toLowerCase())
return filterText.substring(index + searchVal.length)
},
handleSearchNode (node) {
this.currentNodeName = node.name
this.$refs.mindMap.searchNode(node.id)
},
/**
* 选中/取消选中节点
* @param node
*/
handleSelectNode (node) {
this.selectedNodeId = node.id
this.currentNodeName = node.name
this.selectedNode = Object.assign({}, node || {})
},
modalFormOk () {
this.loadData()
},
handleAdd () {
// 需要先选中一个节点
if (!this.selectedNodeId) {
this.$message.warning(this.$t('businessSupport.standardizationActivity.pleaseSelectNode'))
return
}
// 只能加四级
if (this.selectedNode.level + '' === '3') {
this.$message.warning(this.$t('businessSupport.standardizationActivity.addUpToFourLevels'))
return
}
this.$refs.modalForm.add({
pid: this.selectedNodeId,
supperName: this.selectedNode.name,
level: this.selectedNode.level + 1
})
},
handleEdit () {
// 需要先选中一个节点
if (!this.selectedNodeId) {
this.$message.warning(this.$t('businessSupport.standardizationActivity.pleaseSelectNode'))
return
}
this.$refs.modalForm.edit(this.selectedNodeId)
},
handleDetail () {
// 需要先选中一个节点
if (!this.selectedNodeId) {
this.$message.warning(this.$t('businessSupport.standardizationActivity.pleaseSelectNode'))
return
}
this.$refs.modalForm.view(this.selectedNodeId)
},
handleStatistical () {
this.$refs.statisticalDrawer.open()
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
#mountNode {
width: calc(100% - 48px);
height: calc(100% - 56px - 48px);
margin: 0 24px 24px 24px;
}
.search-box {
width: 564px;
padding: 24px 24px 0;
box-sizing: border-box;
}
.search-box-shadow {
box-shadow: rgba(0, 0, 0, 0.15) 2.4px 0 3.2px;
}
.page-icon {
font-size: 21px;
color: @primary-color;
margin-right: 12px;
}
/deep/ .table-page-search-wrapper .ant-form-inline .ant-form-item > .ant-form-item-label {
min-width: unset;
}
/deep/ .title-current-node {
display: inline-block;
font-size: 16px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
color: #4E5969;
margin-left: 12px;
}
/deep/ .page-title-sub-title {
max-width: 15rem;
overflow: hidden;
text-overflow: ellipsis;
}
.page-box {
position: relative;
}
.search-node-list {
position: absolute;
width: 564px;
transition: width .2s linear;
top: 136px;
left: 0;
bottom: 0;
background-color: #FFFFFF;
box-shadow: 2.4px 1px 3.2px rgba(0, 0, 0, 0.15);
box-sizing: border-box;
border-top: 1px solid #E5E6EB;
padding: 8px;
overflow: auto;
z-index: 99;
}
.hide-search {
width: 0;
display: none;
}
.search-node-item {
height: 40px;
line-height: 40px;
padding: 0 12px;
cursor: pointer;
font-size: 14px;
font-family: PingFang SC-Regular, PingFang SC, sans-serif;
color: #1D2129;
}
.search-node-item:hover {
background: rgba(29, 33, 41, 0.06);
}
.highlight-text {
color: @primary-color;
}
.search-overlay {
position: absolute;
top: 56px;
left: 564px;
right: 0;
bottom: 0;
z-index: 98;
}
.custom-operate {
.ant-btn {
margin-left: 12px;
}
.ant-btn:first-child {
margin-left: 0;
}
}
</style>
@@ -0,0 +1,178 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:ok-text="$t('preservation')"
:cancel-text="$t('cancel')"
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<!--联络人-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('system.contact.contactPerson')">
<a-input :placeholder="$t('pleaseEnter') + $t('system.contact.contactPerson')"
:maxLength="50"
v-decorator="['liaison', validatorRules.liaison]" />
</a-form-item>
<!--单位-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.unit')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.unit')"
:maxLength="50"
v-decorator="['unit', validatorRules.unit]" />
</a-form-item>
<!--电话-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.phone')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.phone')"
:maxLength="50"
v-decorator="['phone', validatorRules.phone]" />
</a-form-item>
<!--邮箱-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('user.mailbox')">
<a-input :placeholder="$t('pleaseEnter') + $t('user.mailbox')"
:maxLength="50"
v-decorator="['mailbox', validatorRules.mailbox]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import { phoneReg, isEmail } from '../../../../utils/validate'
export default {
name: 'ContactModal',
data () {
return {
title: this.$t('businessSupport.standardizationActivity.addContactInformation'),
width: 800,
visible: false,
confirmLoading: false,
model: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 联络人
liaison: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('system.contact.contactPerson')
}],
validateTrigger: 'blur'
},
// 单位
unit: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.unit')
}],
validateTrigger: 'blur'
},
// 电话
phone: {
rules: [{
required: true, validator: this.checkPhone
}],
validateTrigger: 'blur'
},
// 邮箱
mailbox: {
rules: [{
required: true, validator: this.checkEmail
}],
validateTrigger: 'blur'
}
}
}
},
methods: {
add () {
this.visible = true
},
view (record) {
this.visible = true
this.model = Object.assign({}, record)
this.disabled = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
handleOk () {
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = Object.assign(this.model, values)
this.$emit('ok', formData)
this.close()
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
this.model = {}
this.form.resetFields()
},
/**
* 校验电话
* @param rule
* @param value
* @param callback
*/
checkPhone (rule, value, callback) {
if (!value) {
// 请输入电话
callback(new Error(this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.phone')))
return
}
if (phoneReg(value)) {
callback()
return
}
// 请输入正确格式的电话
callback(new Error(this.$t('businessSupport.standardizationActivity.pleaseEnterCorrectPhone')))
},
/**
* 校验邮箱
* @param rule
* @param value
* @param callback
*/
checkEmail (rule, value, callback) {
if (!value) {
callback(new Error(this.$t('pleaseEnter') + this.$t('user.mailbox')))
return
}
if (isEmail(value)) {
callback()
return
}
callback(this.$t('user.enterMailboxCorrect'))
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,56 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
@cancel="handleCancel">
<contact-table :data-source="dataSource" :need-row-selection="false" :loading="loading" disabled />
<template slot="footer">
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import ContactTable from '../tables/ContactTable'
import { queryContactList } from '../../../../api/businessSupport'
export default {
name: 'ContactTableModal',
components: { ContactTable },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.contactPersonContactInformation'),
width: 800,
visible: false,
loading: false,
dataSource: []
}
},
methods: {
open (id) {
this.visible = true
this.loading = true
queryContactList({ id }).then(res => {
if (res.success) {
this.dataSource = res.result || []
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,247 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:ok-text="$t('preservation')"
:cancel-text="$t('cancel')"
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<!--我司在工作组排名顺序-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.order')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.order')"
:maxLength="50"
v-decorator="['sort', validatorRules.sort]" />
</a-form-item>
<!--我司人员-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.ourPersonnel')">
<user-selection :placeholder="$t('pleaseSelect') + $t('businessSupport.standardizationActivity.ourPersonnel')"
type="radio"
v-decorator="['personnelId', validatorRules.personnelId]"
:name-str="model.personnel"
@listChange="handleUserChange" />
</a-form-item>
<!--工号-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('user.workNo')">
<a-input :placeholder="$t('pleaseEnter') + $t('user.workNo')"
:maxLength="50"
disabled
v-decorator="['jobNum', validatorRules.jobNum]" />
</a-form-item>
<!--单位-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.unit')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.unit')"
:maxLength="50"
v-decorator="['unit', validatorRules.unit]" />
</a-form-item>
<!--部门-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('department')">
<a-input :placeholder="$t('pleaseEnter') + $t('department')"
:maxLength="50"
disabled
v-decorator="['department', validatorRules.department]" />
</a-form-item>
<!--电话-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.phone')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.phone')"
:maxLength="50"
disabled
v-decorator="['phone', validatorRules.phone]" />
</a-form-item>
<!--邮箱-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('user.mailbox')">
<a-input :placeholder="$t('pleaseEnter') + $t('user.mailbox')"
:maxLength="50"
disabled
v-decorator="['mailbox', validatorRules.mailbox]" />
</a-form-item>
<!--身份-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('user.identity')">
<a-input :placeholder="$t('pleaseEnter') + $t('user.identity')"
:maxLength="50"
v-decorator="['identity', validatorRules.identity]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import UserSelection from '../../../../components/selection/UserSelection'
import { isEmail, phoneReg } from '../../../../utils/validate'
export default {
name: 'GroupModal',
components: { UserSelection },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.addParticipation'),
width: 800,
visible: false,
confirmLoading: false,
model: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 }
},
validatorRules: {
// 我司在工作组排名顺序
sort: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.order') }],
validateTrigger: 'blur'
},
// 我司人员
personnelId: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('businessSupport.standardizationActivity.ourPersonnel')
}],
validateTrigger: 'change'
},
// 工号
jobNum: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('user.workNo') }],
validateTrigger: 'blur'
},
// 单位
unit: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.unit') }],
validateTrigger: 'blur'
},
// 部门
department: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('department') }],
validateTrigger: 'blur'
},
// 电话
phone: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.phone') }],
validateTrigger: 'blur'
},
// 邮箱
mailbox: { rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('user.mailbox') }], validateTrigger: 'blur' },
// 身份
identity: {
rules: [{ required: true, message: this.$t('pleaseEnter') + this.$t('user.identity') }],
validateTrigger: 'blur'
}
},
disabled: false
}
},
methods: {
add () {
this.visible = true
},
view (record) {
this.visible = true
this.model = Object.assign({}, record)
this.disabled = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
handleOk () {
this.form.validateFields((errors, values) => {
if (!errors) {
console.log(JSON.parse(JSON.stringify(this.model)))
console.log(JSON.parse(JSON.stringify(values)))
const formData = Object.assign(this.model, values)
console.log(formData)
this.$emit('ok', formData)
this.close()
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
this.model = {}
this.form.resetFields()
},
handleUserChange (list) {
const data = list[0] || {}
const obj = {
jobNum: data.username, // 工号
mailbox: data.email, // 邮箱
department: data.orgCodeTxt, // 部门
phone: data.phone, // 电话
personnel: data.realname
}
this.model = Object.assign(this.model, obj)
this.form.setFieldsValue(obj)
},
/**
* 校验电话
* @param rule
* @param value
* @param callback
*/
checkPhone (rule, value, callback) {
if (!value) {
// 请输入电话
callback(new Error(this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.phone')))
return
}
if (phoneReg(value)) {
callback()
return
}
// 请输入正确格式的电话
callback(new Error(this.$t('businessSupport.standardizationActivity.pleaseEnterCorrectPhone')))
},
/**
* 校验邮箱
* @param rule
* @param value
* @param callback
*/
checkEmail (rule, value, callback) {
if (!value) {
callback(new Error(this.$t('pleaseEnter') + this.$t('user.mailbox')))
return
}
if (isEmail(value)) {
callback()
return
}
callback(this.$t('user.enterMailboxCorrect'))
},
handleDepartChange (departInfo) {
const names = departInfo.map(tt => {
return tt.text
})
this.model.department_dictText = names.join(',')
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,56 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
@cancel="handleCancel">
<group-table :data-source="dataSource" :need-row-selection="false" :loading="loading" disabled />
<template slot="footer">
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import { queryGroupList } from '../../../../api/businessSupport'
import GroupTable from '../tables/GroupTable'
export default {
name: 'GroupTableModal',
components: { GroupTable },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.groupParticipation'),
width: 800,
visible: false,
loading: false,
dataSource: []
}
},
methods: {
open (id) {
this.visible = true
this.loading = true
queryGroupList({ id }).then(res => {
if (res.success) {
this.dataSource = res.result || []
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,150 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
@cancel="handleCancel">
<a-form :form="form">
<!--参会日期-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('workCenter.postMeetingManageProcess.attendanceDate')">
<j-date :placeholder="$t('pleaseSelect') + $t('workCenter.postMeetingManageProcess.attendanceDate')"
show-type="day"
date-format="YYYY-MM-DD"
:disabled="disabled"
v-decorator="['participationTime', validatorRules.participationTime]" />
</a-form-item>
<!--会议名称-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('workCenter.postMeetingManageProcess.meetingName')">
<a-input :placeholder="$t('pleaseEnter') + $t('workCenter.postMeetingManageProcess.meetingName')"
:maxLength="50"
:disabled="disabled"
v-decorator="['name', validatorRules.name]" />
</a-form-item>
<!--参会人员-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('workCenter.enStandardRevision.conferee')">
<user-selection :placeholder="$t('pleaseSelect') + $t('workCenter.enStandardRevision.conferee')"
:disabled="disabled"
type="checkbox"
:name-str="model.personnel"
v-decorator="['personnelId', validatorRules.personnelId]" @nameChange="handleUserNameChange" />
</a-form-item>
<!--会议资料-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.meetingMaterial')"
v-if="disabled">
<file-echo :file-ids="model.meetingData" />
</a-form-item>
</a-form>
<template slot="footer">
<a-button @click="handleCancel" v-if="disabled">{{ $t('close') }}</a-button>
<template v-else>
<a-button @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button type="primary" @click="handleOk">{{ $t('preservation') }}</a-button>
</template>
</template>
</j-modal>
</template>
<script>
import UserSelection from '../../../../components/selection/UserSelection'
import FileEcho from '../../../../components/FileEcho'
export default {
name: 'MeetingModal',
components: { FileEcho, UserSelection },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.attendanceRecord'),
width: 800,
visible: false,
confirmLoading: false,
model: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 参会日期
participationTime: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('workCenter.postMeetingManageProcess.attendanceDate')
}],
validateTrigger: 'change'
},
// 会议名称
name: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('workCenter.postMeetingManageProcess.meetingName')
}],
validateTrigger: 'blur'
},
// 参会人员
personnelId: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('workCenter.enStandardRevision.conferee')
}],
validateTrigger: 'change'
}
},
disabled: false
}
},
methods: {
add () {
this.disabled = false
this.visible = true
this.model.source = '1'
},
view (record) {
this.visible = true
this.model = Object.assign({}, record)
this.disabled = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
handleOk () {
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = Object.assign(this.model, values)
this.$emit('ok', formData)
this.close()
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
this.model = {}
this.form.resetFields()
},
handleUserNameChange (name) {
this.model.personnel = name
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,56 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
@cancel="handleCancel">
<meeting-table :data-source="dataSource" :need-row-selection="false" :loading="loading" disabled />
<template slot="footer">
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import MeetingTable from '../tables/MeetingTable'
import { queryMeetingList } from '../../../../api/businessSupport'
export default {
name: 'MeetingTableModal',
components: { MeetingTable },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.attendanceRecord'),
width: 800,
visible: false,
loading: false,
dataSource: []
}
},
methods: {
open (id) {
this.visible = true
this.loading = true
queryMeetingList({ id }).then(res => {
if (res.success) {
this.dataSource = res.result || []
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,181 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:ok-text="$t('preservation')"
:cancel-text="$t('cancel')"
@ok="handleOk"
@cancel="handleCancel">
<a-form :form="form">
<!--费用-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.cost')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.cost')"
:maxLength="50"
v-decorator="['fee', validatorRules.fee]" />
</a-form-item>
<!--年份-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.year')">
<j-date :placeholder="$t('pleaseSelect') + $t('businessSupport.standardizationActivity.year')"
show-type="year"
date-format="YYYY"
v-decorator="['year', validatorRules.year]" />
</a-form-item>
<!--状态-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('status')">
<j-dict-select-tag
v-decorator="['state', validatorRules.state]"
:placeholder="$t('pleaseSelect') + $t('status')"
:type="'select'"
:triggerChange="false"
dictCode="pay_state"
@change="handleStateChange" />
</a-form-item>
<!--计划内-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.plan')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.plan')"
:maxLength="50"
v-decorator="['plan', validatorRules.plan]" />
</a-form-item>
<!--缴费方式-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.paymentMethod')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.paymentMethod')"
:maxLength="50"
v-decorator="['pay', validatorRules.pay]" />
</a-form-item>
<!--费用列支-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.expenseReimbursement')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.expenseReimbursement')"
:maxLength="50"
v-decorator="['feeListing', validatorRules.feeListing]" />
</a-form-item>
</a-form>
</j-modal>
</template>
<script>
import { PayState } from '../../../../enums/commonEnums'
export default {
name: 'PaymentModal',
data () {
return {
title: this.$t('businessSupport.standardizationActivity.paymentInfo'),
width: 800,
visible: false,
confirmLoading: false,
model: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 费用
fee: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.cost')
}],
validateTrigger: 'blur'
},
// 年份
year: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('businessSupport.standardizationActivity.year')
}],
validateTrigger: 'change'
},
// 状态
state: {
rules: [{
required: true,
message: this.$t('pleaseSelect') + this.$t('status')
}],
validateTrigger: 'change'
},
// 计划内
plan: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.plan')
}],
validateTrigger: 'blur'
},
// 缴费方式
pay: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.paymentMethod')
}],
validateTrigger: 'blur'
},
// 费用列支
feeListing: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.expenseReimbursement')
}],
validateTrigger: 'blur'
}
}
}
},
methods: {
add () {
this.visible = true
},
view (record) {
this.visible = true
this.model = Object.assign({}, record)
this.disabled = true
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
handleOk () {
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = Object.assign(this.model, values)
this.$emit('ok', formData)
this.close()
}
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
this.model = {}
this.form.resetFields()
},
handleStateChange (value) {
this.model.state_dictText = PayState.nameOfIndex(value)
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,56 @@
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:maskClosable="false"
@cancel="handleCancel">
<payment-table :data-source="dataSource" :need-row-selection="false" :loading="loading" disabled />
<template slot="footer">
<a-button @click="handleCancel">{{ $t('close') }}</a-button>
</template>
</j-modal>
</template>
<script>
import PaymentTable from '../tables/PaymentTable'
import { queryPaymentList } from '../../../../api/businessSupport'
export default {
name: 'PaymentTableModal',
components: { PaymentTable },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.paymentInfo'),
width: 800,
visible: false,
loading: false,
dataSource: []
}
},
methods: {
open (id) {
this.visible = true
this.loading = true
queryPaymentList({ id }).then(res => {
if (res.success) {
this.dataSource = res.result || []
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,351 @@
<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">
<!--基础信息-->
<div class="header-text">{{ $t('basicInformation') }}</div>
<a-form :form="form">
<!--上级节点-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.parentNode')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.parentNode')"
:maxLength="50"
disabled
v-decorator="['supperName', validatorRules.supperName]" />
</a-form-item>
<!--节点类型-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.nodeTypes')">
<j-dict-select-tag :placeholder="$t('pleaseSelect') + $t('businessSupport.standardizationActivity.nodeTypes')"
v-decorator="['standardizationType', validatorRules.standardizationType]"
disabled
dict-code="standardization_type" />
</a-form-item>
<!--编号-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('number')">
<a-input :placeholder="$t('pleaseEnter') + $t('number')"
:maxLength="50"
:disabled="disabled"
v-decorator="['num', validatorRules.num]" />
</a-form-item>
<!--名称-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('name')">
<a-input :placeholder="$t('pleaseEnter') + $t('name')"
:maxLength="50"
:disabled="disabled"
v-decorator="['name', validatorRules.name]" />
</a-form-item>
<!--标准化工作领域-->
<a-form-item :labelCol="labelCol"
:wrapperCol="wrapperCol"
:label="$t('businessSupport.standardizationActivity.standardizationWorkArea')">
<a-input :placeholder="$t('pleaseEnter') + $t('businessSupport.standardizationActivity.standardizationWorkArea')"
:maxLength="100"
:disabled="disabled"
v-decorator="['workingArea', validatorRules.workingArea]" />
</a-form-item>
<!--备注-->
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('remarks')">
<a-textarea :placeholder="$t('pleaseEnter') + $t('remarks')"
:maxLength="500"
:rows="4"
:disabled="disabled"
v-decorator="['notes', validatorRules.notes]" />
</a-form-item>
</a-form>
<!--联络人联系方式-->
<div class="header-text">{{ $t('businessSupport.standardizationActivity.contactPersonContactInformation') }}</div>
<contact-table :data-source="contactDataSource"
:disabled="disabled"
:need-row-selection="!disabled"
@ok="contactModalOk" />
<!--集团参与情况-->
<div class="header-text">{{ $t('businessSupport.standardizationActivity.groupParticipation') }}</div>
<group-table ref="groupTable" :data-source="groupDataSource" :disabled="disabled" :need-row-selection="!disabled" @ok="groupModalOk" />
<!--支付信息-->
<div class="header-text">{{ $t('businessSupport.standardizationActivity.paymentInfo') }}</div>
<payment-table ref="paymentTable"
:data-source="paymentDataSource"
:disabled="disabled"
:need-row-selection="!disabled"
@ok="paymentModalOk" />
<!--参会记录-->
<div class="header-text">{{ $t('businessSupport.standardizationActivity.attendanceRecord') }}</div>
<meeting-table ref="meetingTable"
:data-source="meetingDataSource"
:disabled="disabled"
:need-row-selection="!disabled"
@ok="meetingModalOk" />
</a-spin>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button type="primary" @click="handleOk" v-if="!disabled">{{ $t('determine') }}</a-button>
</div>
</a-drawer>
</template>
<script>
import { StandardizedActivityType } from '../../../../enums/commonEnums'
import JTable from '../../../../components/jero/JTable'
import ContactModal from './ContactModal'
import GroupModal from './GroupModal'
import PaymentModal from './PaymentModal'
import MeetingModal from './MeetingModal'
import { addNode, editNode, queryTableDataById } from '../../../../api/businessSupport'
import ContactTable from '../tables/ContactTable'
import GroupTable from '../tables/GroupTable'
import PaymentTable from '../tables/PaymentTable'
import MeetingTable from '../tables/MeetingTable'
export default {
name: 'StandardizationActivityDrawer',
components: {
JTable,
ContactModal,
GroupModal,
PaymentModal,
MeetingModal,
ContactTable,
GroupTable,
PaymentTable,
MeetingTable
},
data () {
return {
title: this.$t('newlyAdded'),
width: 800,
visible: false,
confirmLoading: false,
model: {},
form: this.$form.createForm(this),
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
},
validatorRules: {
// 上级节点
supperName: {
rules: [{
required: false,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.parentNode')
}],
validateTrigger: 'blur'
},
// 节点类型
standardizationType: {
rules: [{
required: false,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.nodeTypes')
}],
validateTrigger: 'blur'
},
// 编号
num: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('number')
}],
validateTrigger: 'blur'
},
// 名称
name: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('name')
}],
validateTrigger: 'blur'
},
// 标准化工作领域
workingArea: {
rules: [{
required: true,
message: this.$t('pleaseEnter') + this.$t('businessSupport.standardizationActivity.standardizationWorkArea')
}],
validateTrigger: 'blur'
},
// 备注
notes: {
rules: [{
required: false,
message: this.$t('pleaseEnter') + this.$t('remarks')
}]
}
},
// 联络人联系方式表格
contactDataSource: [],
// 集团参与情况
groupDataSource: [],
// 支付信息
paymentDataSource: [],
// 参会记录
meetingDataSource: [],
uploadTable: {}, // 上传文件
disabled: false
}
},
methods: {
add (record) {
this.title = this.$t('newlyAdded')
this.visible = true
this.disabled = false
switch (record.level) {
case 1:
record.standardizationType = StandardizedActivityType.secondLevelBidCommittee.value
break
case 2:
record.standardizationType = StandardizedActivityType.workingTeam.value
break
case 3:
record.standardizationType = StandardizedActivityType.fourLevelBiddingCommittee.value
break
default:
break
}
this.model = Object.assign({}, record)
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
},
edit (id) {
this.title = this.$t('edit')
this.visible = true
this.disabled = false
this.getDetailData(id)
},
view (id) {
this.title = this.$t('view')
this.visible = true
this.disabled = true
this.getDetailData(id)
},
getDetailData (id) {
this.confirmLoading = true
// 获取详情数据
queryTableDataById({ id }).then(res => {
if (res.success) {
const result = res.result || {}
// 基础信息
this.model = Object.assign({}, result.lawsStandardization || {})
this.$nextTick(() => {
this.form.setFieldsValue(this.model)
})
// 联络人联系方式
this.contactDataSource = result.standardizationLiaisonList
// 集团参与情况
this.groupDataSource = result.standardizationGroupList
// 支付信息
this.paymentDataSource = result.standardizationPayments
// 参会记录
this.meetingDataSource = result.standardizationMeetings
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
},
handleOk () {
const groupValidateFlag = this.$refs.groupTable.validateTableData()
const paymentValidateFlag = this.$refs.paymentTable.validateTableData()
const meetingValidateFlag = this.$refs.meetingTable.validateTableData()
if (!groupValidateFlag || !paymentValidateFlag || !meetingValidateFlag) {
return
}
this.form.validateFields((errors, values) => {
if (!errors) {
const formData = {
lawsStandardization: Object.assign(this.model, values), // 基础信息
standardizationLiaisonList: this.contactDataSource, //联络人联系方式
standardizationGroupList: this.groupDataSource, // 集团参与情况
standardizationPayments: this.paymentDataSource, // 支付记录
standardizationMeetings: this.meetingDataSource // 参会记录
}
this.confirmLoading = true
let submitFunc
if (this.model.id) {
submitFunc = editNode
} else {
submitFunc = addNode
}
submitFunc(formData).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
this.form.resetFields()
this.model = {}
this.contactDataSource = []
this.groupDataSource = []
this.paymentDataSource = []
this.meetingDataSource = []
},
contactModalOk (data) {
this.contactDataSource = JSON.parse(JSON.stringify(data))
},
groupModalOk (data) {
this.groupDataSource = JSON.parse(JSON.stringify(data))
},
paymentModalOk (data) {
this.paymentDataSource = JSON.parse(JSON.stringify(data))
},
meetingModalOk (data) {
this.meetingDataSource = JSON.parse(JSON.stringify(data))
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.header-text {
margin-top: 30px;
margin-bottom: 15px;
}
.header-text:first-child {
margin-top: 0;
}
</style>
@@ -0,0 +1,209 @@
<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">
<j-table :scroll="{x: '100%', y: 'calc(100vh - 56px - 61px - 48px - 54px)'}"
:pagination="false"
rowKey="id"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:operation-list="operationList"
@operationClick="operationClick">
</j-table>
</div>
<div class="custom-drawer-style-bottom-btn">
<a-button @click="handleCancel">{{ $t('cancel') }}</a-button>
</div>
<!--联络人联系方式-->
<contact-table-modal ref="contactTableModal" />
<!--集团参与情况-->
<group-table-modal ref="groupTableModal" />
<!--支付信息-->
<payment-table-modal ref="paymentTableModal" />
<!--参会记录-->
<meeting-table-modal ref="meetingTableModal" />
</a-drawer>
</template>
<script>
import JTable from '../../../../components/jero/JTable'
import { queryStatisticalList } from '../../../../api/businessSupport'
import ContactTableModal from './ContactTableModal'
import GroupTableModal from './GroupTableModal'
import PaymentTableModal from './PaymentTableModal'
import MeetingTableModal from './MeetingTableModal'
export default {
name: 'StatisticalListDrawer',
components: { JTable, ContactTableModal, GroupTableModal, PaymentTableModal, MeetingTableModal },
data () {
return {
title: this.$t('businessSupport.standardizationActivity.conferenceStatisticsList'),
width: 1200,
visible: false,
loading: false,
columns: [
// 序号
{
title: this.$t('serialNumber'),
key: 'rowIndex',
width: 60,
customRender: function (t, r, index) {
return parseInt(index) + 1
}
},
// 上级节点
{
title: this.$t('businessSupport.standardizationActivity.parentNode'),
width: 150,
dataIndex: 'supperName'
},
// 节点类型
{
title: this.$t('businessSupport.standardizationActivity.nodeTypes'),
width: 100,
dataIndex: 'standardizationType_dictText'
},
// 编号
{
title: this.$t('number'),
width: 150,
dataIndex: 'num'
},
// 名称
{
title: this.$t('name'),
width: 150,
dataIndex: 'name'
},
// 标准化工作领域
{
title: this.$t('businessSupport.standardizationActivity.standardizationWorkArea'),
width: 130,
dataIndex: 'workingArea'
},
// 备注
{
title: this.$t('remarks'),
width: 150,
dataIndex: 'notes'
},
// 操作
{
title: this.$t('operation'),
align: 'center',
fixed: 'right',
width: 200,
scopedSlots: { customRender: 'action' }
}
],
dataSource: [],
operationList: [
// 联络人联系方式
{
text: this.$t('businessSupport.standardizationActivity.contactPersonContactInformation'),
clickEvent: 'handleViewContact'
// has: 'enterpriseStandardLibrary:plan:delete'
},
// 集团参与情况
{
text: this.$t('businessSupport.standardizationActivity.groupParticipation'),
clickEvent: 'handleViewGroup'
// has: 'enterpriseStandardLibrary:plan:delete'
},
// 支付信息
{
text: this.$t('businessSupport.standardizationActivity.paymentInfo'),
clickEvent: 'handleViewPayment'
// has: 'enterpriseStandardLibrary:plan:delete'
},
// 参会记录
{
text: this.$t('businessSupport.standardizationActivity.attendanceRecord'),
clickEvent: 'handleViewMeeting'
// has: 'enterpriseStandardLibrary:plan:delete'
}
]
}
},
methods: {
open () {
this.visible = true
this.loading = true
queryStatisticalList().then(res => {
if (res.success) {
this.dataSource = res.result || []
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
},
handleCancel () {
this.close()
},
close () {
this.visible = false
},
/**
* 循环操作按钮的操作
* @param operation
* @param record
*/
operationClick (operation, record) {
if (operation.clickEvent === 'handleDelete') {
this.handleDelete(record.id)
} else {
this[operation.clickEvent](record)
}
},
/**
* 查看联络人联系方式
* @param id
*/
handleViewContact ({ id }) {
this.$refs.contactTableModal.open(id)
},
/**
* 查看集团参与情况
* @param id
*/
handleViewGroup ({ id }) {
this.$refs.groupTableModal.open(id)
},
/**
* 查看支付信息
* @param id
*/
handleViewPayment ({ id }) {
this.$refs.paymentTableModal.open(id)
},
/**
* 查看参会记录
* @param id
*/
handleViewMeeting ({ id }) {
this.$refs.meetingTableModal.open(id)
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
</style>
@@ -0,0 +1,131 @@
<template>
<div>
<div class="table-operator" v-if="!disabled">
<a-button type="primary" ghost icon="plus" @click="handleAdd">
{{ $t('businessSupport.standardizationActivity.addContactInformation') }}
</a-button>
<!--删除-->
<a-button type="primary" icon="delete" ghost @click="handleDelete">{{ $t('delete') }}</a-button>
</div>
<j-table v-bind="$attrs"
:scroll="{x: '100%'}"
:pagination="false"
:rowKey="(record,index)=>{return index}"
:columns="columns"
:dataSource="realDataSource"
:row-selection="needRowSelection ? { selectedRowKeys: selectedRowKeys, onChange: onSelectChange } : null">
</j-table>
<!--新增弹框-->
<contact-modal ref="formModal" @ok="formModalOk" />
</div>
</template>
<script>
import JTable from '../../../../components/jero/JTable'
import ContactModal from '../modules/ContactModal'
export default {
name: 'ContactTable',
components: { ContactModal, JTable },
props: {
// 数据
dataSource: {
type: Array,
required: false,
default: () => {
return []
}
},
disabled: {
type: Boolean,
required: false,
default: false
},
// 是否需要行选中
needRowSelection: {
type: Boolean,
required: false,
default: true
}
},
data () {
return {
columns: [
// 联络人
{
title: this.$t('system.contact.contactPerson'),
width: 150,
dataIndex: 'liaison'
},
// 单位
{
title: this.$t('businessSupport.standardizationActivity.unit'),
width: 150,
dataIndex: 'unit'
},
// 电话
{
title: this.$t('businessSupport.standardizationActivity.phone'),
width: 150,
dataIndex: 'phone'
},
// 邮箱
{
title: this.$t('user.mailbox'),
width: 150,
dataIndex: 'mailbox'
}
],
selectedRowKeys: [],
realDataSource: []
}
},
watch: {
dataSource: {
handler (val) {
this.realDataSource = JSON.parse(JSON.stringify(val))
},
immediate: true,
deep: true
}
},
methods: {
// 添加
handleAdd () {
this.$refs.formModal.add()
},
// 删除
handleDelete () {
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('selectAtLeastOne'))
return
}
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
const data = JSON.parse(JSON.stringify(this.realDataSource))
this.selectedRowKeys.forEach(index => {
data[index] = null
})
this.selectedRowKeys = []
this.realDataSource = data.filter(tt => !!tt)
this.$emit('ok', this.realDataSource)
}
})
},
onSelectChange (selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
formModalOk (lineData) {
this.realDataSource.push(lineData)
this.$emit('ok', this.realDataSource)
}
}
}
</script>
<style scoped lang="less">
</style>
@@ -0,0 +1,207 @@
<template>
<div>
<div class="table-operator" v-if="!disabled">
<a-button type="primary" ghost icon="plus" @click="handleAdd">
{{ $t('businessSupport.standardizationActivity.addParticipation') }}
</a-button>
<!--删除-->
<a-button type="primary" icon="delete" ghost @click="handleDelete">{{ $t('delete') }}</a-button>
</div>
<j-table v-bind="$attrs"
:scroll="{x: '100%'}"
:pagination="false"
:rowKey="(record,index)=>{return index}"
:columns="columns"
:dataSource="realDataSource"
:row-selection="needRowSelection ? { selectedRowKeys: selectedRowKeys, onChange: onSelectChange } : null">
<template v-slot:file="{text, record, index}">
<a-button type="primary"
class="button-text"
@click="clickButtonToUpload(text, index, 'feeData')">
{{
(text === 'null' || text === '' || text === null || text === undefined) ? $t('uploadFile.clickUpload') : $t('uploadFile.viewUploadedFiles')
}}
</a-button>
</template>
</j-table>
<!--新增弹框-->
<group-modal ref="formModal" @ok="formModalOk" />
<!--文件上传-->
<upload-file ref="uploadFile" @change="uploadFileChange" :return-url="false" :disabled="disabled" />
</div>
</template>
<script>
import JTable from '../../../../components/jero/JTable'
import GroupModal from '../modules/GroupModal'
import ContactModal from '../modules/ContactModal'
import UploadFile from '../../../../components/UploadFile'
export default {
name: 'GroupTable',
components: { UploadFile, ContactModal, JTable, GroupModal },
props: {
// 数据
dataSource: {
type: Array,
required: false,
default: () => {
return []
}
},
disabled: {
type: Boolean,
required: false,
default: false
},
// 是否需要行选中
needRowSelection: {
type: Boolean,
required: false,
default: true
}
},
data () {
return {
columns: [
// 我司在工作组排名顺序
{
title: this.$t('businessSupport.standardizationActivity.order'),
width: 200,
dataIndex: 'sort'
},
// 我司人员
{
title: this.$t('businessSupport.standardizationActivity.ourPersonnel'),
width: 150,
dataIndex: 'personnel'
},
// 工号
{
title: this.$t('user.workNo'),
width: 150,
dataIndex: 'jobNum'
},
// 单位
{
title: this.$t('businessSupport.standardizationActivity.unit'),
width: 150,
dataIndex: 'unit'
},
// 部门
{
title: this.$t('department'),
width: 150,
dataIndex: 'department'
},
// 电话
{
title: this.$t('businessSupport.standardizationActivity.phone'),
width: 150,
dataIndex: 'phone'
},
// 邮箱
{
title: this.$t('user.mailbox'),
width: 150,
dataIndex: 'mailbox'
},
// 身份
{
title: this.$t('user.identity'),
width: 150,
dataIndex: 'identity'
},
// 资料
{
title: this.$t('businessSupport.standardizationActivity.data'),
width: 150,
dataIndex: 'feeData',
scopedSlots: { customRender: 'file' }
}
],
selectedRowKeys: [],
realDataSource: [],
uploadTable: {}
}
},
watch: {
dataSource: {
handler (val) {
this.realDataSource = JSON.parse(JSON.stringify(val))
},
immediate: true,
deep: true
}
},
methods: {
// 添加
handleAdd () {
this.$refs.formModal.add()
},
// 删除
handleDelete () {
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('selectAtLeastOne'))
return
}
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
const data = JSON.parse(JSON.stringify(this.realDataSource))
this.selectedRowKeys.forEach(index => {
data[index] = null
})
this.selectedRowKeys = []
this.realDataSource = data.filter(tt => !!tt)
this.$emit('ok', this.realDataSource)
}
})
},
onSelectChange (selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
formModalOk (lineData) {
this.realDataSource.push(lineData)
this.$emit('ok', this.realDataSource)
},
// 点击点击上传按钮
clickButtonToUpload (fileIds, index, dbFieldName) {
this.$refs.uploadFile.open(fileIds)
this.uploadTable = { index, dbFieldName }
},
// 文件上传改变后的回调
uploadFileChange (data) {
console.log(data)
const attIdList = []
if (data && data.length > 0) {
data.map(item => {
attIdList.push(item.id)
})
}
/** 赋值给当前对应的表单文件 */
this.$set(this.realDataSource[this.uploadTable.index], this.uploadTable.dbFieldName, attIdList.join(','))
this.$emit('ok', this.realDataSource)
},
/**
* 校验文件是否上传
* @returns {boolean}
*/
validateTableData () {
return true
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.button-text {
width: 100%;
}
</style>
@@ -0,0 +1,211 @@
<template>
<div>
<div class="table-operator" v-if="!disabled">
<a-button type="primary" ghost icon="plus" @click="handleAdd">
{{ $t('businessSupport.standardizationActivity.addAttendanceRecord') }}
</a-button>
<!--删除-->
<a-button type="primary" icon="delete" ghost @click="handleDelete">{{ $t('delete') }}</a-button>
</div>
<j-table v-bind="$attrs"
:scroll="{x: '100%'}"
:pagination="ipagination"
rowKey="tableRowKey"
:columns="columns"
:dataSource="realDataSource"
:row-selection="needRowSelection ? { selectedRowKeys: selectedRowKeys, onChange: onSelectChange } : null"
@change="handleTableChange">
<template v-slot:file="{text, record, index}">
<!--会后资料如果数据从流程来就是查看如果是新增的就正常显示上传-->
<a-button type="primary"
class="button-text"
@click="clickButtonToUpload(text, index, 'meetingData')" v-if="record.source !== '2'">
{{
(text === 'null' || text === '' || text === null || text === undefined) ? $t('uploadFile.clickUpload') : $t('uploadFile.viewUploadedFiles')
}}
<a></a>
</a-button>
<div class="action-span-cell" v-else>
<a @click="handleView(record)">{{ $t('view') }}</a>
</div>
</template>
</j-table>
<!--新增弹框-->
<meeting-modal ref="formModal" @ok="formModalOk" />
<!--文件上传-->
<upload-file ref="uploadFile" @change="uploadFileChange" :return-url="false" :disabled="disabled" />
</div>
</template>
<script>
import UploadFile from '../../../../components/UploadFile'
import JTable from '../../../../components/jero/JTable'
import MeetingModal from '../modules/MeetingModal'
export default {
name: 'MeetingTable',
components: { MeetingModal, JTable, UploadFile },
props: {
// 数据
dataSource: {
type: Array,
required: false,
default: () => {
return []
}
},
disabled: {
type: Boolean,
required: false,
default: false
},
// 是否需要行选中
needRowSelection: {
type: Boolean,
required: false,
default: true
}
},
data () {
return {
columns: [
// 参会日期
{
title: this.$t('workCenter.postMeetingManageProcess.attendanceDate'),
width: 150,
dataIndex: 'participationTime'
},
// 会议名称
{
title: this.$t('workCenter.postMeetingManageProcess.meetingName'),
width: 150,
dataIndex: 'name'
},
// 参会人员
{
title: this.$t('workCenter.enStandardRevision.conferee'),
width: 150,
dataIndex: 'personnel'
},
// 会议资料
{
title: this.$t('businessSupport.standardizationActivity.meetingMaterial'),
width: 150,
dataIndex: 'meetingData',
scopedSlots: { customRender: 'file' }
}
],
selectedRowKeys: [],
realDataSource: [],
uploadTable: {},
/* 分页参数 */
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
}
}
},
watch: {
dataSource: {
handler (val) {
this.realDataSource = JSON.parse(JSON.stringify(val)).map((item, index) => {
item.tableRowKey = index
return item
})
},
immediate: true,
deep: true
}
},
methods: {
// 添加
handleAdd () {
this.$refs.formModal.add()
},
// 删除
handleDelete () {
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('selectAtLeastOne'))
return
}
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
const data = JSON.parse(JSON.stringify(this.realDataSource))
this.selectedRowKeys.forEach(tableRowKey => {
const index = data.findIndex(tt => tt && tt.tableRowKey === tableRowKey)
data[index] = null
})
this.selectedRowKeys = []
this.realDataSource = data.filter(tt => !!tt)
this.$emit('ok', this.realDataSource)
}
})
},
onSelectChange (selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
formModalOk (lineData) {
lineData.tableRowKey = this.realDataSource && this.realDataSource.length > 0 ? this.realDataSource[this.realDataSource.length - 1].tableRowKey + 1 : 0
this.realDataSource.push(lineData)
this.$emit('ok', this.realDataSource)
},
// 点击点击上传按钮
clickButtonToUpload (fileIds, index, dbFieldName) {
this.$refs.uploadFile.open(fileIds)
this.uploadTable = { index, dbFieldName }
},
// 文件上传改变后的回调
uploadFileChange (data) {
console.log(data)
const attIdList = []
if (data && data.length > 0) {
data.map(item => {
attIdList.push(item.id)
})
}
/** 赋值给当前对应的表单文件 */
this.$set(this.realDataSource[this.uploadTable.index], this.uploadTable.dbFieldName, attIdList.join(','))
this.$emit('ok', this.realDataSource)
},
handleView (record) {
this.$refs.formModal.view(record)
},
handleTableChange (pagination) {
this.ipagination = pagination
},
/**
* 校验文件是否上传
* @returns {boolean}
*/
validateTableData () {
if (this.realDataSource.some(tt => !tt.meetingData)) {
this.$message.warning(this.$t('businessSupport.standardizationActivity.pleaseUploadMeeting'))
return false
}
return true
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.button-text {
width: 100%;
}
</style>
@@ -0,0 +1,199 @@
<template>
<div>
<div class="table-operator" v-if="!disabled">
<a-button type="primary" ghost icon="plus" @click="handleAdd">
{{ $t('businessSupport.standardizationActivity.addPaymentInfo') }}
</a-button>
<!--删除-->
<a-button type="primary" icon="delete" ghost @click="handleDelete">{{ $t('delete') }}</a-button>
</div>
<j-table v-bind="$attrs"
:scroll="{x: '100%'}"
:pagination="false"
:rowKey="(record,index)=>{return index}"
:columns="columns"
:dataSource="realDataSource"
:row-selection="needRowSelection ? { selectedRowKeys: selectedRowKeys, onChange: onSelectChange } : null">
<template v-slot:file="{text, record, index}">
<a-button type="primary"
class="button-text"
@click="clickButtonToUpload(text, index, 'feeData')">
{{
(text === 'null' || text === '' || text === null || text === undefined) ? $t('uploadFile.clickUpload') : $t('uploadFile.viewUploadedFiles')
}}
</a-button>
</template>
</j-table>
<!--新增弹框-->
<payment-modal ref="formModal" @ok="formModalOk" />
<!--文件上传-->
<upload-file ref="uploadFile" @change="uploadFileChange" :return-url="false" :disabled="disabled" />
</div>
</template>
<script>
import UploadFile from '../../../../components/UploadFile'
import JTable from '../../../../components/jero/JTable'
import PaymentModal from '../modules/PaymentModal'
export default {
name: 'PaymentTable',
components: { PaymentModal, JTable, UploadFile },
props: {
// 数据
dataSource: {
type: Array,
required: false,
default: () => {
return []
}
},
disabled: {
type: Boolean,
required: false,
default: false
},
// 是否需要行选中
needRowSelection: {
type: Boolean,
required: false,
default: true
}
},
data () {
return {
columns: [
// 费用
{
title: this.$t('businessSupport.standardizationActivity.cost'),
width: 150,
dataIndex: 'fee'
},
// 年份
{
title: this.$t('businessSupport.standardizationActivity.year'),
width: 150,
dataIndex: 'year'
},
// 状态
{
title: this.$t('status'),
width: 150,
dataIndex: 'state_dictText'
},
// 计划内
{
title: this.$t('businessSupport.standardizationActivity.plan'),
width: 150,
dataIndex: 'plan'
},
// 缴费方式
{
title: this.$t('businessSupport.standardizationActivity.paymentMethod'),
width: 150,
dataIndex: 'pay'
},
// 费用列支
{
title: this.$t('businessSupport.standardizationActivity.expenseReimbursement'),
width: 150,
dataIndex: 'feeListing'
},
// 资料
{
title: this.$t('businessSupport.standardizationActivity.data'),
width: 150,
dataIndex: 'feeData',
scopedSlots: { customRender: 'file' }
}
],
selectedRowKeys: [],
realDataSource: [],
uploadTable: {}
}
},
watch: {
dataSource: {
handler (val) {
this.realDataSource = JSON.parse(JSON.stringify(val))
},
immediate: true,
deep: true
}
},
methods: {
// 添加
handleAdd () {
this.$refs.formModal.add()
},
// 删除
handleDelete () {
if (!this.selectedRowKeys || this.selectedRowKeys.length === 0) {
this.$message.warning(this.$t('selectAtLeastOne'))
return
}
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
const data = JSON.parse(JSON.stringify(this.realDataSource))
this.selectedRowKeys.forEach(index => {
data[index] = null
})
this.selectedRowKeys = []
this.realDataSource = data.filter(tt => !!tt)
this.$emit('ok', this.realDataSource)
}
})
},
onSelectChange (selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
formModalOk (lineData) {
this.realDataSource.push(lineData)
this.$emit('ok', this.realDataSource)
},
// 点击点击上传按钮
clickButtonToUpload (fileIds, index, dbFieldName) {
this.$refs.uploadFile.open(fileIds)
this.uploadTable = { index, dbFieldName }
},
// 文件上传改变后的回调
uploadFileChange (data) {
console.log(data)
const attIdList = []
if (data && data.length > 0) {
data.map(item => {
attIdList.push(item.id)
})
}
/** 赋值给当前对应的表单文件 */
this.$set(this.realDataSource[this.uploadTable.index], this.uploadTable.dbFieldName, attIdList.join(','))
this.$emit('ok', this.realDataSource)
},
/**
* 校验文件是否上传
* @returns {boolean}
*/
validateTableData() {
if (this.realDataSource.some(tt => !tt.feeData)) {
this.$message.warning(this.$t('businessSupport.standardizationActivity.pleaseUploadPaymentInfo'))
return false
}
return true
}
}
}
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.button-text {
width: 100%;
}
</style>