[add] 企标评审会记录

This commit is contained in:
lideqin
2023-09-11 15:10:56 +08:00
parent 6814f80daa
commit ce03708101
6 changed files with 781 additions and 7 deletions
+6 -1
View File
@@ -23,6 +23,9 @@ const collectStandard = (params) => getAction('', params)
// 分享企标
const shareStandard = (params) => getAction('', params)
// 企标评审会记录
const setQualityStandard = (params) => getAction('', params)
export {
getEnterpriseStandardTableHeader,
getEnterpriseStandardSearchForm,
@@ -34,5 +37,7 @@ export {
initChange,
temporaryPermissionSet,
collectStandard,
shareStandard
shareStandard,
setQualityStandard
}
@@ -19,6 +19,26 @@ module.exports = {
submitQuestion: '提交问题',
standardResolutionSheet: '标准分解单'
},
// 评审会记录
reviewMeeting: {
enterpriseStandardName: '企标名称',
enterpriseStandardNum: '企标编号',
reviewData: '评审日期',
setQualityStandard: '设置优质标准',
reviewDetail: '评分详情',
principalDrafter: '主起草人',
mainDraftUnit: '主起草单位',
reviewer: '评审人',
average: '平均总分',
isQuality: '是否推荐为优质标准',
selectMaxTen: '请最多选择10条',
scoreDetailTitle: '企标详情',
project: '项目',
desc: '描述',
score: '分值',
grade: '评分',
groundsForDemerit: '扣分理由'
},
// 宣贯
publicize: {
enterpriseStandardNum: '企标编号',
@@ -0,0 +1,224 @@
<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('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardNum')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter')+$t('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardNum')" v-model="queryParam.standardNo"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item :label="$t('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardName')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-input :placeholder="$t('pleaseEnter')+$t('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardName')" v-model="queryParam.standardName"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item :label="$t('enterpriseStandardLibrary.reviewMeeting.reviewData')" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-range-picker
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
@change="reviewDataChange"
v-model="queryParam.reviewData">
</a-range-picker>
</a-form-item>
</a-col>
<div style="float: right;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">{{ $t('query') }}</a-button>
<a-button type="primary" @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="setting" type="primary" ghost @click="handleSetGood">
{{ $t('enterpriseStandardLibrary.reviewMeeting.setQualityStandard') }}
</a-button>
</div>
<div>
<j-table
:can-drag="true"
:scroll="{x: '100%'}"
ref="table"
size="middle"
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<!-- 企标编号/企标名称 -->
<template v-slot:enterpriseStandardNum="{text, record}">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<a class="link-a" @click="handleGoDetail(record)">{{ text }}</a>
</a-tooltip>
</template>
<!-- 操作栏 -->
<div slot="action" slot-scope="{text, record}" class="action-span-cell">
<a @click="handleEdit(record)" class="table-ope-btn">{{ $t('edit') }}</a>
<a @click="handleReviewDetail(record)" class="table-ope-btn">{{ $t('enterpriseStandardLibrary.reviewMeeting.reviewDetail') }}</a>
</div>
</j-table>
<review-meeting-modal ref="modalForm" @ok="modalFormOk"></review-meeting-modal>
<score-detail ref="scoreDetail" @ok="loadData"></score-detail>
</div>
</a-card>
</template>
<script>
import JTable from '@/components/jero/JTable'
import { JeroListMixin } from '@/mixins/JeroListMixin'
import { setQualityStandard } from '@/api/enterpriseStandardLibraryApi'
import ScoreDetail from './modules/ScoreDetail'
import ReviewMeetingModal from './modules/ReviewMeetingModal'
export default {
name: 'ReviewMeetingList',
components: { ReviewMeetingModal, ScoreDetail, JTable },
mixins: [JeroListMixin],
data () {
return {
labelCol: {
span: 4
},
wrapperCol: {
span: 18
},
columns: [
{
title: this.$t('serialNumber'),
dataIndex: '',
key: 'rowIndex',
width: 60,
align: 'center',
customRender: function (t, r, index) {
return parseInt(index) + 1
}
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardNum'),
align: 'center',
width: 180,
dataIndex: 'standardNo',
scopedSlots: { customRender: 'enterpriseStandardNum' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.enterpriseStandardName'),
align: 'center',
width: 180,
dataIndex: 'standardName',
scopedSlots: { customRender: 'enterpriseStandardName' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.principalDrafter'),
align: 'center',
width: 180,
dataIndex: 'principalDrafter',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.mainDraftUnit'),
align: 'center',
width: 180,
dataIndex: 'mainDraftUnit',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.reviewData'),
align: 'center',
width: 180,
dataIndex: 'reviewData',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.reviewer'),
align: 'center',
width: 180,
dataIndex: 'declareUserName',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.average'),
align: 'center',
width: 180,
dataIndex: 'declareFileName',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.isQuality'),
align: 'center',
width: 180,
dataIndex: 'isQuality',
scopedSlots: { customRender: 'text' }
},
{
title: this.$t('operation'),
scopedSlots: { customRender: 'action' },
align: 'center',
width: 170
}
],
url: {
list: '/enterprise/reviewMeeting/page'
}
}
},
methods: {
// 评审日期改变
reviewDataChange (val) {
this.queryParam.reviewStartDate = val[0]
this.queryParam.reviewEndDate = val[1]
},
// 点击跳转企标详情
handleGoDetail (record) {
this.$openPageNewSheet({
path: '/enterpriseStandardLibrary/enterpriseStandardDetail',
query: {
id: record.id
}
})
},
// 设置优质标准
handleSetGood () {
if (this.selectedRowKeys.length <= 0) {
this.$message.warning(this.$t('selectLeastOne'))
return
}
if (this.selectedRowKeys.length > 10) {
this.$message.warning(this.$t('selectMaxTen'))
return
}
const param = {}
param.ids = this.selectedRowKeys.join(',')
setQualityStandard(param).then(res => {
if (res.success) {
this.$message.success(res.message)
} else {
this.$message.warning(res.message)
}
})
},
// 点击评分详情
handleReviewDetail (record) {
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,103 @@
<template>
<a-modal
:title="title"
:maskClosable="true"
:width="800"
:closable="true"
@cancel="handleCancel"
@ok="handleOk"
:visible="visible">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandardLibrary.reviewMeeting.isQuality')">
<j-dict-select-tag
v-decorator.trim="[ 'isQuality', validatorRules.isQuality]">
</j-dict-select-tag>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import pick from 'lodash.pick'
import { postAction } from '@/api/manage'
import JDictSelectTag from '@/components/dict/JDictSelectTag'
export default {
name: 'ReviewMeetingModal',
components: { JDictSelectTag },
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: 16 }
},
validatorRules: {
isQuality: {
rules: [
{ required: false, message: this.$t('pleaseEnter') + this.$t('enterpriseStandardLibrary.standard.authorizationDepart') }
],
validateTrigger: 'change'
}
},
url: {
edit: ''
}
}
},
methods: {
edit (record) {
this.visible = true
this.form.resetFields()
this.model = Object.assign({}, record)
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model, 'isQuality'))
})
},
handleCancel () {
this.close()
},
handleOk () {
if (this.confirmLoading) return
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
const param = Object.assign({}, values)
param.id = this.model.id
postAction(this.url.edit, param).then(res => {
if (res.success) {
this.$message.success(res.success)
this.$emit('ok')
this.visible = false
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
close () {
this.visible = false
this.model = {}
}
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,422 @@
<template>
<a-modal
:title="title"
:maskClosable="true"
:width="1000"
:closable="true"
@cancel="handleCancel"
:footer="false"
:visible="visible">
<a-spin :spinning="confirmLoading">
<div class="content-wrapper">
<div class="left-wrapper">
<div v-for="item in nameArr" :key="item" class="name-div">
<a-button class="left-btn" :type="leftCurr === item ? 'primary' : ''" @click="leftChange(item)">{{ item }}</a-button>
</div>
</div>
<div class="right-wrapper">
<a-table
bordered
:scroll="{x: '100%'}"
:columns="columns"
:dataSource="dataSource"
rowKey="id"
:pagination="false"
>
<template slot="text" slot-scope="text">
<a-tooltip overlay-class-name="tooltip-style">
<template slot="title">{{ text || text === 0 ? text : global.emptyLine }}</template>
<div>{{ text || text === 0 ? text : global.emptyLine }}</div>
</a-tooltip>
</template>
</a-table>
</div>
</div>
</a-spin>
</a-modal>
</template>
<script>
const fixDataSourse = [
{
id: 1,
project: '文本格式(15)',
desc: '评估标准文件的格式是否符合GB/T 1.1的要求,包括文件名、编号、版本号、' +
'发布日期、生效日期、引用文件章节、图表等内容是否齐全、准确、清晰。',
score: '一般',
scoreRange: '0~5'
},
{
id: 2,
score: '优秀',
scoreRange: '6~10'
},
{
id: 3,
score: '优秀',
scoreRange: '11~15'
},
{
id: 4,
project: '标准内容(45)',
desc: '评估标准文件的内容是否详细准确、内容详实、逻辑清晰、科学合理。包括术语定义、' +
'引用标准、技术要求、试验检测方法等各个方面是否符合/严于法律法规、国家标准、行业标准等要求。',
score: '一般',
scoreRange: '0~20'
},
{
id: 5,
score: '优秀',
scoreRange: '21~35'
},
{
id: 6,
score: '优秀',
scoreRange: '36~45'
},
{
id: 7,
project: '适用性 (10)',
desc: '评估标准文件的应用范围是否明确、适用,是否与研发工艺、质量、生产、采购等环节相符合。',
score: '一般',
scoreRange: '0~3'
},
{
id: 8,
score: '优秀',
scoreRange: '4~6'
},
{
id: 9,
score: '优秀',
scoreRange: '7~10'
},
{
id: 10,
project: '完整性 (15)',
desc: '评估标准文件所涉及的专业领域是否全面、系统,是否涵盖了所有相关模版' +
'(比如设计规范模版、释放规范模版、产品技术条件模版)所规定的要素和环节。',
score: '一般',
scoreRange: '0~5'
},
{
id: 11,
score: '优秀',
scoreRange: '6~10'
},
{
id: 12,
score: '优秀',
scoreRange: '11~15'
},
{
id: 13,
project: '可读性 (5)',
desc: '评估标准文件的可读性是否良好,是否有错别字,是否易于阅读和理解。',
score: '一般',
scoreRange: '0~2'
},
{
id: 14,
score: '优秀',
scoreRange: '3~4'
},
{
id: 15,
score: '优秀',
scoreRange: '5'
},
{
id: 16,
project: '权威性及可执行性(10)',
desc: '评估标准文件的权威性是否足够,是否得到了相关方的认可和信任,是否得到了有效的贯彻和执行。',
score: '一般',
scoreRange: '0~3'
},
{
id: 17,
score: '优秀',
scoreRange: '4~6'
},
{
id: 18,
score: '优秀',
scoreRange: '7~10'
}
]
const initData = {
'60.00': null,
'test_chh(00712)': [
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '1',
evaluateScore: '10',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
},
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '2',
evaluateScore: '11',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
},
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '3',
evaluateScore: '12',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
},
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '4',
evaluateScore: '13',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
},
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '5',
evaluateScore: '14',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
},
{
id: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
orgCode: null,
reviewMeetingId: null,
evaluateItem: '6',
evaluateScore: '15',
adjudicatorId: null,
adjudicatorName: 'test_chh(00712)',
deductionScoreReason: '无'
}
]
}
export default {
name: 'ScoreDetail',
data () {
return {
title: this.$t('enterpriseStandardLibrary.reviewMeeting.scoreDetailTitle'),
visible: false,
confirmLoading: false,
scoreData: {},
nameArr: [],
leftCurr: '',
columns: [
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.project'),
align: 'center',
width: 100,
dataIndex: 'project',
customRender: (text, row, index) => {
const obj = {
children: text || this.global.emptyLine,
attrs: {}
}
if (index % 3 === 0) {
obj.attrs.rowSpan = 3
} else if (index % 3 !== 0 && index !== 19) {
obj.attrs.rowSpan = 0
}
if (index === 19) {
obj.attrs.colSpan = 6
}
return obj
}
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.desc'),
align: 'center',
// width: 100,
dataIndex: 'desc',
customRender: (text, row, index) => {
const obj = {
children: text || this.global.emptyLine,
attrs: {}
}
if (index % 3 === 0) {
obj.attrs.rowSpan = 3
} else if (index % 3 !== 0 && index !== 19) {
obj.attrs.rowSpan = 0
}
if (index === 19) {
obj.attrs.colSpan = 0
}
return obj
}
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.score'),
align: 'center',
width: 100,
dataIndex: 'score',
colSpan: 2,
customRender: (text, row, index) => {
const obj = {
children: text || this.global.emptyLine,
attrs: {}
}
if (index === 19) {
obj.attrs.colSpan = 0
}
return obj
}
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.score'),
align: 'center',
width: 100,
dataIndex: 'scoreRange',
colSpan: 0
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.grade'),
align: 'center',
width: 100,
dataIndex: 'evaluateScore',
customRender: (text, row, index) => {
const obj = {
children: text || this.global.emptyLine,
attrs: {}
}
if (index === 19) {
obj.attrs.colSpan = 0
}
if (index % 3 === 0) {
obj.attrs.rowSpan = 3
} else {
obj.attrs.rowSpan = 0
}
return obj
}
},
{
title: this.$t('enterpriseStandardLibrary.reviewMeeting.groundsForDemerit'),
align: 'center',
width: 100,
dataIndex: 'deductionScoreReason',
customRender: (text, row, index) => {
const obj = {
children: text || this.global.emptyLine,
attrs: {}
}
if (index === 19) {
obj.attrs.colSpan = 0
}
if (index % 3 === 0) {
obj.attrs.rowSpan = 3
} else {
obj.attrs.rowSpan = 0
}
return obj
}
}
],
dataSource: []
}
},
mounted () {
this.initData()
},
watch: {
leftCurr: {
immediate: true,
handler (val) {
console.log('leftCurr改变')
if (val) {
// 左侧选中改变,右侧表格数据也随之改变
const dataArr = this.scoreData[val]
if (dataArr) {
for (const i in fixDataSourse) {
this.dataSource[i] = { ...fixDataSourse[i] }
if (i % 3 === 0) {
this.dataSource[i].evaluateScore = dataArr[Math.floor(i / 3)].evaluateScore || ''
this.dataSource[i].deductionScoreReason = dataArr[Math.floor(i / 3)].deductionScoreReason || ''
}
}
} else {
this.dataSource = [...fixDataSourse]
}
}
}
}
},
methods: {
initData () {
this.scoreData = initData
this.nameArr = Object.keys(this.scoreData)
this.leftCurr = this.nameArr[0]
},
// 左侧选中改变
leftChange (value) {
this.leftCurr = value
},
// 通过
handleCancel () {
this.visible = false
}
}
}
</script>
<style scoped lang="less">
.content-wrapper {
display: flex;
.left-wrapper {
width: 20%;
display: flex;
flex-direction: column;
align-items: center;
.left-btn {
margin-bottom: 10px;
}
}
.right-wrapper {
width: 80%;
}
}
</style>
@@ -10,7 +10,7 @@
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandard.enterpriseStandard.authorizationDepart')">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandardLibrary.standard.authorizationDepart')">
<j-select-depart
v-decorator.trim="[ 'deptIds', validatorRules.deptIds]"
:multi="true"
@@ -18,14 +18,14 @@
:treeOpera="true">
</j-select-depart>
</a-form-item>
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandard.enterpriseStandard.authorizationUser')">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandardLibrary.standard.authorizationUser')">
<user-selection
v-decorator.trim="[ 'userIds', validatorRules.userIds]"
:nameStr="model.userNames"
@nameChange="userSelectNameChange">
</user-selection>
</a-form-item>
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandard.enterpriseStandard.maturityDate')">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" :label="$t('enterpriseStandardLibrary.standard.maturityDate')">
<a-date-picker
v-decorator.trim="[ 'maturityDate', validatorRules.maturityDate]"
format="YYYY-MM-DD"
@@ -63,19 +63,19 @@ export default {
validatorRules: {
deptIds: {
rules: [
{ required: false, message: this.$t('pleaseEnter') + this.$t('enterpriseStandard.enterpriseStandard.authorizationDepart') }
{ required: false, message: this.$t('pleaseEnter') + this.$t('enterpriseStandardLibrary.standard.authorizationDepart') }
],
validateTrigger: 'change'
},
userIds: {
rules: [
{ required: false, message: this.$t('pleaseEnter') + this.$t('enterpriseStandard.enterpriseStandard.authorizationUser') }
{ required: false, message: this.$t('pleaseEnter') + this.$t('enterpriseStandardLibrary.standard.authorizationUser') }
],
validateTrigger: 'change'
},
notes: {
rules: [
{ required: true, message: this.$t('pleaseEnter') + this.$t('enterpriseStandard.enterpriseStandard.maturityDate') }
{ required: true, message: this.$t('pleaseEnter') + this.$t('enterpriseStandardLibrary.standard.maturityDate') }
],
validateTrigger: 'change'
}