TemplateDetails.vue 39 KB

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