TemplateDetails copy.vue 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. <template>
  2. <div class="box boxMinHeight">
  3. <header class="header">
  4. <div class="header-content flex-box-ce">
  5. <!-- 返回按钮 -->
  6. <div class="flex-box-ce header-left">
  7. <i class="el-icon-arrow-left fontColorC" @click="$router.go(-1)"></i>
  8. <el-tooltip class="item" effect="dark" :content="templateTitle" placement="bottom">
  9. <div class="text fontColorB font-flex-word">{{ templateTitle }}</div>
  10. </el-tooltip>
  11. <el-popover ref="popoverRef" placement="right" width="400" trigger="click">
  12. <div class="flex-box-ce">
  13. <el-input v-model="title" placeholder="请输入模板名称" size="small"></el-input>
  14. <el-button type="primary" size="small" style="margin-left: 10px;"
  15. @click="editTitle()">确定</el-button>
  16. </div>
  17. <i class="el-icon-edit" slot="reference" style="margin-left: 10px; color: #999;"></i>
  18. </el-popover>
  19. </div>
  20. <!-- 发布按钮 -->
  21. <div class="header-right">
  22. <!-- 某一个指标标题为空,或者评分,审批不开启,不能发起考核 -->
  23. <el-button type="primary" @click="publish" :disabled="isTitleNull || isScoreNull">发布考核</el-button>
  24. </div>
  25. </div>
  26. </header>
  27. <div style="height: 1px; background-color: #DCDFE6; margin-top: 5px;"></div>
  28. <el-alert class="bounce animated" type="warning" :title="alertTilte" :closable="false" show-icon
  29. style="width: 100%; margin-top: 10px;"></el-alert>
  30. <div class="flex-box-ce" style="justify-content: space-between; margin-top: 10px;">
  31. <div class="flex-box-ce">
  32. <el-button type="primary" size="small" @click="addData()">添加指标</el-button>
  33. <el-button type="danger" :disabled="!(multipleSelection && multipleSelection.length > 0)"
  34. @click="confirmDelete()" size="small">批量删除</el-button>
  35. </div>
  36. <div class="flex-box-ce" style="padding: 0 20px; color: #999;">
  37. <el-popover placement="right" trigger="hover" class="popover" @show="showPopover">
  38. <div class="flex-box-ce" style="width: 200px; justify-content: space-between;">
  39. <el-checkbox v-model="checkAll" @change="checkAllChangeFn">全选</el-checkbox>
  40. <el-button type="text" @click="reset(true)">重置</el-button>
  41. </div>
  42. <div style="height: 1px; background-color: #DCDFE6; margin: 5px 0;"></div>
  43. <el-checkbox-group v-model="checkColumns" @change="changeColumns"
  44. style="width: 200px; display: flex; flex-direction: column;">
  45. <el-checkbox v-for="(item, key) in this.tableColumn" :label="item.label"
  46. :key="item.label"></el-checkbox>
  47. </el-checkbox-group>
  48. <div class="flex-box-ce" slot="reference">
  49. <i class="el-icon-s-tools" style="margin-right: 5px;"></i>流程节点展示
  50. </div>
  51. </el-popover>
  52. </div>
  53. </div>
  54. <el-table :data="tableData" ref="fmeaTableRef" v-table-move="['fmeaTableRef']" v-loading="loading" stripe
  55. style="width: 100%; margin-top: 10px;" border :header-cell-style="{ background: '#f5f7fa' }"
  56. @selection-change="handleSelectChange" :height="600">
  57. <el-table-column type="selection"></el-table-column>
  58. <template v-for="item in tableColumn">
  59. <el-table-column v-if="item.isShow && item.label === '规则'" :key="item.prop" :prop="item.prop"
  60. :label="item.label" align="center" :min-width="item.width">
  61. <template slot-scope="scope">
  62. <el-tooltip v-if="scope.row.content" class="item" effect="dark" placement="top">
  63. <div v-html="scope.row.content" slot="content"
  64. style="max-width: 300px; white-space: pre-line;">
  65. </div>
  66. <div class="oneLine"
  67. @click="editContent(scope.$index, scope.row.content, scope.row.indicatorId)">
  68. {{ scope.row.content }}
  69. </div>
  70. </el-tooltip>
  71. <el-button v-else
  72. @click="editContent(scope.$index, scope.row.content, scope.row.indicatorId)">编辑规则</el-button>
  73. </template>
  74. </el-table-column>
  75. <el-table-column v-else-if="item.isShow && ['目标', '权重(%)'].includes(item.label)" :key="item.prop"
  76. :prop="item.prop" :label="item.label" align="center" :min-width="item.width">
  77. <template slot-scope="scope">
  78. <el-input v-model="scope.row[item.prop]" :placeholder="item.label" clearable
  79. @blur="handleEdit(item.prop, scope.row[item.prop], scope.row.indicatorId)"
  80. oninput="value=value.replace(/[^\d.]/g,'')"></el-input>
  81. </template>
  82. </el-table-column>
  83. <el-table-column v-else-if="item.isShow && item.label === '计算公式'" prop="formulae" label="计算公式"
  84. align="center" min-width="130">
  85. <template slot-scope="scope">
  86. <el-button @click="openFormula(scope.row, scope.$index)">
  87. {{ scope.row.expression && scope.row.expression.formulas.length > 0 ? `公式
  88. ${scope.row.expression.formulas.length} 条` : '公式' }}
  89. </el-button>
  90. </template>
  91. </el-table-column>
  92. <el-table-column v-else-if="item.isShow && ['指标', '单位'].includes(item.label)" :key="item.prop"
  93. :prop="item.prop" :label="item.label" align="center" :min-width="item.width">
  94. <template slot-scope="scope">
  95. <el-input v-model="scope.row[item.prop]" :placeholder="item.label" clearable
  96. @blur="handleEdit(item.prop, scope.row[item.prop], scope.row.indicatorId)"></el-input>
  97. </template>
  98. </el-table-column>
  99. <el-table-column v-if="item.isShow && flowColumn.includes(item.label)" :key="item.prop"
  100. :prop="item.prop" :label="item.label" :render-header="(h, obj) => renderHeader(h, item, item.prop)"
  101. align="center" :min-width="item.width" fixed="right">
  102. <template slot-scope="scope">
  103. <template v-if="item.label === '确认目标'">
  104. <el-switch v-if="!scope.row.flow.nodes[0].enable" :value="scope.row.flow.nodes[0].enable"
  105. @input="handleStatusChange(-1, scope.row, 'targetConfirms')"></el-switch>
  106. <ShowDataComp v-else-if="scope.row.flow.nodes[0].enable && isDataShow"
  107. :show-data="scope.row.flow.nodes[0]" :select-nodes="scope.row"
  108. @btnClick="handleBtnClick" />
  109. </template>
  110. <template v-if="item.label === '录入结果'">
  111. <el-switch v-if="!scope.row.flow.nodes[1].enable" :value="scope.row.flow.nodes[1].enable"
  112. @input="handleStatusChange(-1, scope.row, 'resultInput')"></el-switch>
  113. <ShowDataComp v-else-if="scope.row.flow.nodes[1].enable && isDataShow"
  114. :show-data="scope.row.flow.nodes[1]" :select-nodes="scope.row"
  115. @btnClick="handleBtnClick" />
  116. </template>
  117. <template v-if="item.label === '自评'">
  118. <el-switch v-model="scope.row.flow.nodes[2].enable"
  119. @change="handleScoreSelf(scope.row, scope.$index)"></el-switch>
  120. </template>
  121. <template v-if="item.label === '互评'">
  122. <el-switch :value="scope.row.flow.nodes[3].enable"
  123. @input="handleStatusChange(-1, scope.row, 'scoreEachOther')"></el-switch>
  124. </template>
  125. <template v-if="item.label === '评分'">
  126. <el-switch v-if="!scope.row.flow.nodes[4].enable" :value="scope.row.flow.nodes[4].enable"
  127. @input="handleStatusChange(-1, scope.row, 'scores')"></el-switch>
  128. <ShowDataComp v-else-if="scope.row.flow.nodes[4].enable && isDataShow"
  129. :show-data="scope.row.flow.nodes[4]" :select-nodes="scope.row"
  130. @btnClick="handleBtnClick" />
  131. </template>
  132. <template v-if="item.label === '审批'">
  133. <el-switch v-if="!scope.row.flow.nodes[5].enable" :value="scope.row.flow.nodes[5].enable"
  134. @input="handleStatusChange(-1, scope.row, 'reviews')"></el-switch>
  135. <ShowDataComp v-else-if="scope.row.flow.nodes[5].enable && isDataShow"
  136. :show-data="scope.row.flow.nodes[5]" :select-nodes="scope.row"
  137. @btnClick="handleBtnClick" />
  138. </template>
  139. <template v-if="item.label === '抄送'">
  140. <el-switch v-if="!scope.row.flow.nodes[6].enable" :value="scope.row.flow.nodes[6].enable"
  141. @input="handleStatusChange(-1, scope.row, 'cc')"></el-switch>
  142. <ShowDataComp v-else-if="scope.row.flow.nodes[6].enable && isDataShow"
  143. :show-data="scope.row.flow.nodes[6]" :select-nodes="scope.row"
  144. @btnClick="handleBtnClick" />
  145. </template>
  146. </template>
  147. </el-table-column>
  148. </template>
  149. </el-table>
  150. <div style="height: 50px;"></div>
  151. <!-- <TiptapComp /> -->
  152. <!-- 编辑流程节点 -->
  153. <!-- <HandleNode v-if="currentIndicator" v-model="dialogVisible" :form-label="formLabel" :dialog-title="dialogTitle"
  154. :node-type="nodeType" :template-id="templateId" :select-nodes="selectNodes"
  155. :indicator-id="selectIndicatorId" @closeDialog="closeDialog" :tag-index="tagIndex"
  156. @onConfirm="finishHandle" /> -->
  157. <!-- 编辑计算公式 -->
  158. <FormulaComp v-if="showFormula" v-model="showFormula"
  159. :fixed-props="[{ key: 'target', name: '目标' }, { key: 'weight', name: '权重' }, { key: 'result', name: '结果值' }]"
  160. :expressions-props="currentIndicator.expression.formulas || []" @onConfirm="onFormulaConfirm" />
  161. <!-- 发布考核弹框 -->
  162. <PublishComp v-if="showPublish" v-model="showPublish" :template-ids="[templateId]" @onConfirm="onPubishConfirm" />
  163. <!-- 编辑规则 -->
  164. <EditContentComp v-if="showEditContent" v-model="showEditContent" :content="content"
  165. :indicator-id="selectIndicatorId" :template-id="templateId" @finishEdit="finishEditContent" />
  166. <!-- 批量修改流程节点 -->
  167. <BatchHandleNode v-if="batchHandleDialog" v-model="batchHandleDialog" :template-id="templateId"
  168. :form-label="formLabel" :dialog-title="dialogTitle" :node-type="nodeType" :handle-node="handleNode"
  169. @onConfirm="finishBatchHandle" />
  170. <!-- 编辑确认目标节点 -->
  171. <TargetConfirms v-if="targetConfirms" v-model="targetConfirms" :form-label="formLabel"
  172. :dialog-title="dialogTitle" :node-type="nodeType" :template-id="templateId" :select-nodes="selectNodes"
  173. :indicator-id="selectIndicatorId" @closeDialog="closeDialog" :tag-index="tagIndex"
  174. @onConfirm="finishHandle" />
  175. <!-- 编辑录入结果节点 -->
  176. <ResultInput v-if="resultInput" v-model="resultInput" :form-label="formLabel" :dialog-title="dialogTitle"
  177. :node-type="nodeType" :template-id="templateId" :select-nodes="selectNodes"
  178. :indicator-id="selectIndicatorId" @closeDialog="closeDialog" :tag-index="tagIndex"
  179. @onConfirm="finishHandle" />
  180. <!-- 编辑互评节点 -->
  181. <ScoreEachOther v-if="scoreEachOther" v-model="scoreEachOther" :form-label="formLabel"
  182. :dialog-title="dialogTitle" :node-type="nodeType" :template-id="templateId" :select-nodes="selectNodes"
  183. :indicator-id="selectIndicatorId" @closeDialog="closeDialog" :tag-index="tagIndex"
  184. @onConfirm="finishHandle" />
  185. <!-- 编辑评分节点 -->
  186. <Scores v-if="scores" v-model="scores" :form-label="formLabel" :dialog-title="dialogTitle" :node-type="nodeType"
  187. :template-id="templateId" :select-nodes="selectNodes" :indicator-id="selectIndicatorId"
  188. @closeDialog="closeDialog" :tag-index="tagIndex" @onConfirm="finishHandle" />
  189. <Reviews v-if="reviews" v-model="reviews" :form-label="formLabel" :dialog-title="dialogTitle" :node-type="nodeType"
  190. :template-id="templateId" :select-nodes="selectNodes" :indicator-id="selectIndicatorId"
  191. @closeDialog="closeDialog" :tag-index="tagIndex" @onConfirm="finishHandle" />
  192. <!-- 编辑审批节点 -->
  193. <CC v-if="cc" v-model="cc" :form-label="formLabel" :dialog-title="dialogTitle"
  194. :node-type="nodeType" :template-id="templateId" :select-nodes="selectNodes"
  195. :indicator-id="selectIndicatorId" @closeDialog="closeDialog" :tag-index="tagIndex"
  196. @onConfirm="finishHandle" />
  197. </div>
  198. </template>
  199. <script>
  200. import { mapGetters } from 'vuex';
  201. import FormulaComp from '@/newPerformance/components/TemplateDetails/FormulaComp'; // 计算公式弹框
  202. import HandleNode from '@/newPerformance/components/TemplateDetails/HandleNode'; //单独设置流程节点弹框
  203. import PublishComp from '@/newPerformance/components/TemplateDetails/PublishComp'; // 发布考核弹框
  204. import ShowDataComp from '@/newPerformance/components/PublicComp/ShowData'; // 显示节点数据组件
  205. import EditContentComp from '@/newPerformance/components/TemplateDetails/EditContent'; // 编辑规则组件
  206. import BatchHandleNode from '@/newPerformance/components/TemplateDetails/BatchHandleNode'; // 批量设置流程节点
  207. import TargetConfirms from '@/newPerformance/components/TemplateDetails/TargetConfirms'; // 确认目标流程节点
  208. import ResultInput from '@/newPerformance/components/TemplateDetails/ResultInput'; // 结果录入流程节点
  209. import ScoreEachOther from '@/newPerformance/components/TemplateDetails/ScoreEachOther'; // 互评流程节点
  210. import Scores from '@/newPerformance/components/TemplateDetails/Scores'; // 评分流程节点
  211. import Reviews from '@/newPerformance/components/TemplateDetails/Reviews'; // 审批流程节点
  212. import CC from '@/newPerformance/components/TemplateDetails/CC'; // 审批流程节点
  213. export default {
  214. components: {
  215. HandleNode,
  216. FormulaComp,
  217. PublishComp,
  218. ShowDataComp,
  219. EditContentComp,
  220. BatchHandleNode,
  221. TargetConfirms,
  222. ResultInput,
  223. ScoreEachOther,
  224. Scores,
  225. Reviews,
  226. CC
  227. },
  228. data() {
  229. return {
  230. isDataShow: false,
  231. isShow: false,
  232. templateTitle: "默认标题",
  233. loading: false,
  234. title: "默认标题",
  235. alertTilte: "可在表格中直接编辑指标,规则 (规则支持富文本) ,目标,单位,权重,计算公式以及流程节点, 注意: 每个指标的标题不能为空!每个指标的评分节点一定要开启!",
  236. templateId: "", // 模板ID
  237. tableData: [], // 表格数据
  238. showFormula: false, // 编辑计算公式弹框显示
  239. showPublish: false, // 发布考核弹框显示
  240. dialogVisible: false, // 编辑流程节点弹框显示
  241. dialogTitle: "", // 编辑流程节点弹框标题
  242. isDisable: false, // 是否禁用
  243. nodeType: "", // 节点类型
  244. currentIndicator: null, // 操作的指标
  245. selectIndicatorId: "", // 选择的指标ID
  246. selectNodes: [], // 选中指标所有的节点
  247. selectIndex: 0, // 表格行索引
  248. formLabel: "",
  249. tagIndex: 0,
  250. multipleSelection: [],
  251. content: "", // 指标规则
  252. showEditContent: false, // 编辑指标内容弹框
  253. deptList: [], // 部门列表 - 树形结构
  254. dept_list: [], // 部门列表
  255. postList: [], // 岗位列表
  256. flowColumn: ["确认目标", "录入结果", "自评", "互评", "评分", "审批", "抄送"],
  257. tableColumn: [
  258. { label: "指标", prop: "title", isShow: true, width: 150 },
  259. { label: "规则", prop: "content", isShow: true, width: 150 },
  260. { label: "目标", prop: "target", isShow: true, width: 150},
  261. { label: "单位", prop: "unit", isShow: true, width: 100 },
  262. { label: "权重(%)", prop: "weight", isShow: true, width: 100 },
  263. { label: "计算公式", prop: "formulae", isShow: true, width: 100 },
  264. { label: "确认目标", prop: "targetConfirms", isShow: false, width: 100 },
  265. { label: "录入结果", prop: "resultInput", isShow: false, width: 100 },
  266. { label: "自评", prop: "scoreSelf", isShow: false, width: 100 },
  267. { label: "互评", prop: "scoreEachOther", isShow: false, width: 100 },
  268. { label: "评分", prop: "scores", isShow: false, width: 100 },
  269. { label: "审批", prop: "reviews", isShow: false, width: 100 },
  270. { label: "抄送", prop: "cc", isShow: false, width: 100 }
  271. ],
  272. checkColumns: [],
  273. checkAll: false,
  274. flowInfo: {},
  275. handleNode: {},
  276. batchHandleDialog: false,
  277. targetConfirms: false,
  278. resultInput: false,
  279. scoreEachOther: false,
  280. scores: false,
  281. reviews: false,
  282. cc: false
  283. }
  284. },
  285. computed: {
  286. ...mapGetters(['user_info']),
  287. // 指标标题为空不能发起考核
  288. isTitleNull() {
  289. return this.tableData.find(item => item.title == '' || item.title == null) ? true : false
  290. },
  291. // 指标评分为禁用不能发起考核
  292. isScoreNull() {
  293. return this.tableData.find(item => !item.flow.nodes[4].enable) ? true : false
  294. }
  295. },
  296. created() {
  297. this.templateId = this.$route.params.templateDetailId;
  298. this.get_template_detail();
  299. this.get_table_data();
  300. this.isDataShow = false
  301. // 请求岗位列表,部门列表
  302. Promise.all([this.get_dept_list(), this.get_post_list()]).then(([deptRes, postRes]) => {
  303. if (deptRes.data.code !== 1) return this.$message.error(deptRes.data.msg || "请求部门列表数据出错")
  304. if (postRes.data.code !== 1) return this.$message.error(postRes.data.msg || "请求岗位列表数据出错")
  305. this.dept_list = deptRes.data.data.list;
  306. this.deptList = this.getTreeData(this.dept_list); // 处理成树状结构
  307. this.postList = postRes.data.data.list
  308. localStorage.setItem("dept_list", JSON.stringify(this.dept_list))
  309. localStorage.setItem("deptList", JSON.stringify(this.deptList))
  310. localStorage.setItem("postList", JSON.stringify(this.postList))
  311. this.isDataShow = true
  312. })
  313. },
  314. methods: {
  315. // 处理部门树状结构数据
  316. getTreeData(data) {
  317. for (var i = 0; i < data.length; i++) {
  318. data[i].checked = false;
  319. if (data[i].children.length < 1) {
  320. // children若为空数组,则将children设为undefined
  321. data[i].children = undefined;
  322. } else {
  323. // children若不为空数组,则继续 递归调用 本方法
  324. this.getTreeData(data[i].children);
  325. }
  326. }
  327. return data;
  328. },
  329. // 获取部门
  330. get_dept_list() {
  331. return this.$axiosUser('get', '/api/pro/department/tree', '', 'v2')
  332. },
  333. // 岗位列表
  334. get_post_list() {
  335. let data = {
  336. page: 1,
  337. page_size: 999,
  338. cate_id: -1,
  339. name: ''
  340. }
  341. return this.$axiosUser('get', '/api/pro/post/cate_post_list', data)
  342. },
  343. // 自定义表头
  344. renderHeader(h, item, type) {
  345. let label = ""
  346. const labels = {
  347. 'targetConfirms': '确认目标',
  348. 'resultInput': '录入结果',
  349. 'scoreSelf': '自评',
  350. 'scoreEachOther': '互评',
  351. 'scores': '评分',
  352. 'reviews': '审批',
  353. 'cc': '抄送'
  354. }
  355. label = labels[type];
  356. let that = this;
  357. return h('div', {
  358. style: { display: "flex", alignItems: "center", justifyContent: "center" }
  359. }, [
  360. h('el-button', {
  361. props: {
  362. size: 'small'
  363. },
  364. on: {
  365. click: function () {
  366. that.clickButton(type);
  367. }
  368. }
  369. }, label),
  370. ])
  371. },
  372. clickButton(nodeType) {
  373. this.handleNode = this.flowInfo.nodes.find(node => node.type === nodeType)
  374. let options = {
  375. 'targetConfirms': ['确认目标', '确认人'],
  376. 'resultInput': ['录入结果', '录入人'],
  377. 'scoreSelf': ['自评', ''],
  378. 'scoreEachOther': ['互评', '互评人'],
  379. 'scores': ['评分', '评分人'],
  380. 'reviews': ['审批', '审批人'],
  381. 'cc': ['抄送', '抄送人']
  382. }
  383. this.dialogTitle = options[nodeType][0]
  384. this.formLabel = options[nodeType][1]
  385. this.nodeType = nodeType; // 节点类型
  386. this.batchHandleDialog = true;
  387. },
  388. // 打开编辑规则内容弹框
  389. editContent(index, content, indicatorId) {
  390. this.selectIndex = index;
  391. this.content = content;
  392. this.selectIndicatorId = indicatorId;
  393. this.showEditContent = true
  394. },
  395. finishEditContent(content) {
  396. this.tableData[this.selectIndex].content = content
  397. },
  398. // 获取模板详情
  399. get_template_detail() {
  400. this.$axiosUser("get", `/performance/template/info/${this.user_info.site_id}/` + this.templateId).then(res => {
  401. let { data: { data: { title, flow } } } = res
  402. this.templateTitle = title || '默认标题'
  403. this.title = title || '默认标题'
  404. this.flowInfo = flow || {}
  405. })
  406. },
  407. // 获取表格数据
  408. get_table_data() {
  409. this.loading = true
  410. this.$axiosUser("get", `/performance/indicator/list/${this.user_info.site_id}/` + this.templateId).then(res => {
  411. this.loading = false
  412. this.tableData = res.data.data.list
  413. })
  414. },
  415. editTableData() {
  416. },
  417. // 编辑模板标题
  418. editTitle() {
  419. let title = this.title
  420. if (title !== null && title !== '') {
  421. let url = `/performance/template/title/${this.user_info.site_id}`
  422. this.$http.post(url, { templateId: this.templateId, title }).then(res => {
  423. if (res.code == 1) {
  424. this.$refs.popoverRef && this.$refs.popoverRef.doClose();
  425. this.get_template_detail();
  426. }
  427. })
  428. }
  429. },
  430. // 编辑指标名称,规则,权重,目标,单位
  431. handleEdit(props, value, id) {
  432. let url = '', data = {};
  433. url = `/performance/indicator/${props}/${this.user_info.site_id}/${this.templateId}`;
  434. data[props] = value;
  435. data['indicatorId'] = id;
  436. this.$http.post(url, data).then(res => {
  437. if(res.code == 0) return this.$message.error(res.msg || '操作失败')
  438. })
  439. },
  440. handleBtnClick(index, node, row) {
  441. this.handleStatusChange(index, row, node.type)
  442. },
  443. // 自评节点单独操作
  444. handleScoreSelf(row, index) {
  445. let { indicatorId, flow: { nodes } } = row
  446. let data = {
  447. indicatorId, // 指标ID
  448. nodes
  449. }
  450. let url = `/performance/indicator/flow/${this.user_info.site_id}/${this.templateId}`
  451. this.$http.post(url, data).then(res => {
  452. let { code, data } = res
  453. if (code == 1) {
  454. this.tableData.splice(index, 1, data); //替换元素
  455. this.$message.success("操作成功");
  456. } else {
  457. this.$message.error(res.message || '操作失败');
  458. }
  459. })
  460. },
  461. // 操作节点
  462. handleStatusChange(index, row, nodeType) {
  463. if (index !== -1) this.tagIndex = index // 子节点索引
  464. this.currentIndicator = row;
  465. let { indicatorId } = row;
  466. this.selectIndicatorId = indicatorId; // 指标ID
  467. this.selectNodes = row.flow.nodes; // 所有节点
  468. this.nodeType = nodeType; // 节点类型
  469. if (nodeType == 'targetConfirms') {
  470. this.dialogTitle = "确认目标"
  471. this.formLabel = "确认人"
  472. this.targetConfirms = true;
  473. }
  474. if (nodeType == 'resultInput') {
  475. this.dialogTitle = "录入结果11"
  476. this.formLabel = "录入人"
  477. this.resultInput = true;
  478. }
  479. if (nodeType == 'scoreSelf') {
  480. this.dialogTitle = "自评"
  481. }
  482. if (nodeType == 'scoreEachOther') {
  483. this.dialogTitle = "互评"
  484. this.formLabel = "互评人"
  485. this.scoreEachOther = true
  486. }
  487. if (nodeType == 'scores') {
  488. this.dialogTitle = "评分"
  489. this.formLabel = "评分人"
  490. this.scores = true
  491. }
  492. if (nodeType == 'reviews') {
  493. this.dialogTitle = "审批"
  494. this.formLabel = "审批人"
  495. this.reviews = true
  496. }
  497. if (nodeType == 'cc') {
  498. this.dialogTitle = "抄送"
  499. this.formLabel = "抄送人"
  500. this.cc = true
  501. }
  502. // this.dialogVisible = true;
  503. },
  504. // 添加指标
  505. addData() {
  506. let url = `/performance/indicator/create/${this.user_info.site_id}/${this.templateId}`
  507. this.$http.post(url, {}).then(res => {
  508. let { data, code } = res
  509. if (code) this.tableData.push(data)
  510. })
  511. },
  512. handleSelectChange(val) {
  513. this.multipleSelection = val;
  514. },
  515. // 取消删除
  516. cancelDelete() {
  517. console.log("取消删除");
  518. },
  519. // 确认删除
  520. confirmDelete() {
  521. if (this.multipleSelection && this.multipleSelection.length > 0) {
  522. this.$confirm('确定删除选中的指标吗?', '提示', {
  523. type: 'warning'
  524. }).then(() => {
  525. // 创建一个包含异步任务的数组,每个任务都是一个 axios 请求
  526. const arrays = []
  527. this.multipleSelection.forEach(item => {
  528. arrays.push(this.deleteIndicator(item))
  529. })
  530. // 当所有请求都成功完成时,responses 是一个包含所有响应的数组
  531. Promise.all(arrays).then(responses => {
  532. // console.log(responses)
  533. this.get_table_data();
  534. }).catch(error => {
  535. // 如果任何一个请求失败,将会进入这个 catch 块
  536. console.log(error)
  537. })
  538. }).catch(() => { });
  539. }
  540. },
  541. // 删除指标
  542. deleteIndicator(item) {
  543. let url = `/performance/indicator/remove/${this.user_info.site_id}/${this.templateId}/${item.indicatorId}`
  544. return this.$axiosUser('post', url).then(res => {
  545. // if (res.data.code == 1) this.get_table_data();
  546. return res.data
  547. })
  548. },
  549. // 打开计算公式弹框
  550. openFormula(row, index) {
  551. this.currentIndicator = null;
  552. this.selectIndex = -1;
  553. this.currentIndicator = row;
  554. this.selectIndex = index;
  555. this.showFormula = true;
  556. },
  557. // 关闭编辑计算公式弹框
  558. closeDialog() {
  559. },
  560. // 全选复选框事件监听
  561. checkAllChangeFn(val) {
  562. if (val) {
  563. // 全选
  564. this.tableColumn.forEach(item => {
  565. item.isShow = true
  566. })
  567. } else {
  568. // 反全选
  569. this.tableColumn.forEach(item => {
  570. if (this.flowColumn.includes(item.label)) {
  571. item.isShow = false;
  572. } else {
  573. item.isShow = true
  574. }
  575. })
  576. }
  577. this.showPopover();
  578. },
  579. // 重置,flag: Boolean,全部重置为flag
  580. reset(flag) {
  581. this.tableColumn.forEach(item => {
  582. if (this.flowColumn.includes(item.label)) {
  583. item.isShow = false;
  584. } else {
  585. item.isShow = true
  586. }
  587. })
  588. this.showPopover();
  589. this.refreshTable();
  590. },
  591. // 表格列是否显示的方法
  592. showColumn(currentColumn) {
  593. return this.tableColumn.find(item => item.prop == currentColumn).isShow;
  594. },
  595. /* 选择列 */
  596. changeColumns(val) {
  597. this.tableColumn.forEach(item => {
  598. item.isShow = false;
  599. })
  600. // columns将val数组存在的值设为true,不存在的设为false
  601. val && val.forEach(item => {
  602. let current = this.tableColumn.find(i => i.label == item)
  603. current.isShow = true;
  604. })
  605. // 判断是否全选
  606. this.judgeIsCheckAll();
  607. // this.refreshTable();
  608. },
  609. // 重新渲染表格
  610. refreshTable() {
  611. this.$nextTick(() => {
  612. if (this.$refs.fmeaTableRef) this.$refs.fmeaTableRef.doLayout();
  613. })
  614. },
  615. // 气泡框出现
  616. showPopover() {
  617. this.checkColumns = []
  618. this.tableColumn.forEach(item => {
  619. if (item.isShow) {
  620. this.checkColumns.push(item.label)
  621. }
  622. })
  623. // 判断是否全选
  624. this.judgeIsCheckAll();
  625. },
  626. // 判断是否全选
  627. judgeIsCheckAll() {
  628. // 选中的长度 = 表格列的长度 全选按钮就选中
  629. if (this.checkColumns.length == this.tableColumn.length)
  630. this.checkAll = true
  631. else
  632. this.checkAll = false
  633. },
  634. finishHandle(nodes) {
  635. let data = nodes
  636. let url = `/performance/indicator/flow/${this.user_info.site_id}/${this.templateId}`
  637. this.$http.post(url, data).then(res => {
  638. let { code, data } = res
  639. if (code == 1) {
  640. let { indicatorId } = this.currentIndicator;
  641. let index = this.tableData.findIndex(table => table.indicatorId === indicatorId)
  642. this.tableData.splice(index, 1, data); //替换元素
  643. this.$message.success("操作成功");
  644. this.nodeType = ''
  645. this.dialogTitle = ''
  646. this.selectNodes = []
  647. this.currentIndicator = []
  648. this.selectIndicatorId = ''
  649. this.tagIndex = -1
  650. } else {
  651. this.$message.error(res.message || '操作失败');
  652. }
  653. })
  654. },
  655. // 批量操作成功
  656. finishBatchHandle(data) {
  657. this.flowInfo = data;
  658. this.get_table_data();
  659. },
  660. // 编辑计算公式确定的回调
  661. onFormulaConfirm(formulas) {
  662. let url = `/performance/indicator/expression/${this.user_info.site_id}/${this.templateId}`;
  663. let { indicatorId } = this.currentIndicator;
  664. let params = {
  665. indicatorId,
  666. expression: {
  667. formulas: formulas.map(item => {
  668. return {
  669. condition: item.condition,
  670. expression: item.expression
  671. }
  672. })
  673. }
  674. }
  675. this.$http.post(url, params).then(res => {
  676. let { data, code } = res
  677. if (code) {
  678. this.tableData.splice(this.selectIndex, 1, data); //替换元素
  679. }
  680. })
  681. },
  682. // 发布考核
  683. publish() {
  684. this.showPublish = true;
  685. },
  686. // 发布考核弹框的回调
  687. onPubishConfirm(params) {
  688. let templateId = this.templateId;
  689. let { title, startDate, endDate, cycleType, employeeIds, okrs, cateId } = params
  690. let employees = employeeIds.map(employee => ({
  691. employeeId: employee,
  692. ids: [],
  693. interviewFlow: {
  694. nodes: [
  695. {
  696. id: "IT_1894283564934688769",
  697. type: "interview",
  698. allows: [],
  699. enable: false,
  700. weight: 0,
  701. children: [],
  702. assigneeIds: [],
  703. leaderLevel: 1,
  704. assigneeType: "self",
  705. multipleType: "or"
  706. }
  707. ]
  708. }
  709. }))
  710. let requireParams = {
  711. title,
  712. cycleType,
  713. startDate,
  714. endDate,
  715. okrs,
  716. templates: [
  717. {
  718. templateId,
  719. employees
  720. }
  721. ],
  722. cateId
  723. }
  724. // let url = `/performance/review/publish/${this.user_info.site_id}`;
  725. // console.log(requireParams)
  726. let url = `/performance/review/publish/templates/${this.user_info.site_id}`;
  727. this.loading = true
  728. this.$http.post(url, requireParams).then(res => {
  729. console.log(res)
  730. let { data, code } = res
  731. this.loading = false
  732. if (code == 1) {
  733. this.$message.success("发布成功");
  734. setTimeout(() => {
  735. this.$router.go(-1)
  736. }, 1000);
  737. }
  738. })
  739. }
  740. }
  741. };
  742. </script>
  743. <style lang="scss">
  744. .box {
  745. .el-switch__core {
  746. width: 30px !important;
  747. height: 16px;
  748. }
  749. .el-switch__core::after {
  750. width: 14px;
  751. height: 14px;
  752. margin-top: -1px;
  753. }
  754. .el-switch.is-checked .el-switch__core::after {
  755. margin-left: -15px;
  756. }
  757. }
  758. </style>
  759. <style scoped="scoped" lang="scss">
  760. .oneLine {
  761. overflow: hidden;
  762. white-space: nowrap;
  763. text-overflow: ellipsis;
  764. }
  765. .box {
  766. padding: 0 20px;
  767. font-size: 14px;
  768. background-color: #fff;
  769. box-sizing: border-box;
  770. border-radius: 4px;
  771. /* 设置滚动条的宽度和背景色 */
  772. ::v-deep .el-table__body-wrapper::-webkit-scrollbar {
  773. width: 10px;
  774. height: 10px;
  775. background-color: #f9f9f9;
  776. }
  777. /* 设置滚动条滑块的样式 */
  778. ::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb {
  779. border-radius: 6px;
  780. background-color: #c1c1c1;
  781. }
  782. /* 设置滚动条滑块hover样式 */
  783. ::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb:hover {
  784. background-color: #a8a8a8;
  785. }
  786. /* 设置滚动条轨道的样式 */
  787. ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {
  788. box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
  789. border-radius: 6px;
  790. background: #ededed;
  791. }
  792. /*头部样式*/
  793. .header-content {
  794. position: relative;
  795. box-sizing: border-box;
  796. height: 60px;
  797. justify-content: space-between;
  798. .header-left {
  799. width: 230px;
  800. box-sizing: border-box;
  801. height: 60px;
  802. cursor: pointer;
  803. .el-icon-arrow-left {
  804. font-size: 22px;
  805. }
  806. &:hover {
  807. .el-icon-arrow-left {
  808. background-color: #f5f7fa;
  809. color: #222;
  810. }
  811. }
  812. .text {
  813. font-size: 16px;
  814. font-weight: 600;
  815. padding-left: 50px;
  816. &::before {
  817. position: absolute;
  818. content: '';
  819. width: 1px;
  820. height: 36px;
  821. background-color: #ebebeb;
  822. left: 44px;
  823. top: 50%;
  824. margin-top: -18px;
  825. }
  826. }
  827. }
  828. .header-right {
  829. width: 230px;
  830. text-align: right;
  831. }
  832. }
  833. .plus-button {
  834. display: block;
  835. margin: 20px auto;
  836. }
  837. }
  838. </style>