exceltab.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. <template>
  2. <basic-container>
  3. <div class="search-box">
  4. <div class="search-box-left">
  5. <el-input v-model="query.name" placeholder="请输入名称" style="width: 200px;" class="filter-item" size="small"/>
  6. <el-select v-model="query.projectId" placeholder="项目名称" clearable style="width: 200px" class="filter-item" size="small">
  7. <el-option v-for="item in projectList" :key="item.id" :label="item.projectAlias" :value="item.id" />
  8. </el-select>
  9. <el-select v-model="query.tabType" placeholder="模板类型" clearable style="width: 200px" class="filter-item" size="small">
  10. <el-option v-for="item in tabTypeList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  11. </el-select>
  12. <el-select v-model="query.tableTemplateType" placeholder="项目类型" clearable style="width: 200px" class="filter-item" size="small">
  13. <el-option v-for="item in tableTemplateTypeList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  14. </el-select>
  15. <el-button type="primary" @click="searchClick" class="custom-primary-btn" size="small">搜索</el-button>
  16. <el-button type="info" @click="clearSearch" size="small">清空</el-button>
  17. </div>
  18. <div class="header-box-right">
  19. <el-button type="primary" icon="el-icon-plus" @click="addClick" size="small">新增</el-button>
  20. <el-button type="warning" icon="el-icon-sort" @click="handleSort" size="small">排序</el-button>
  21. <el-button type="danger" icon="el-icon-delete" @click="handleDelete" size="small">删除</el-button>
  22. </div>
  23. </div>
  24. <avue-crud
  25. :option="option"
  26. :table-loading="loading"
  27. :data="data"
  28. :page.sync="page"
  29. :permission="permissionList"
  30. :before-open="beforeOpen"
  31. v-model="form"
  32. ref="crud"
  33. @row-update="rowUpdate"
  34. @row-save="rowSave"
  35. @row-del="rowDel"
  36. @search-change="searchChange"
  37. @search-reset="searchReset"
  38. @selection-change="selectionChange"
  39. @current-change="currentChange"
  40. @size-change="sizeChange"
  41. @refresh-change="refreshChange"
  42. @on-load="onLoad"
  43. :search.sync="query"
  44. >
  45. <template
  46. slot-scope="scope"
  47. slot="menu"
  48. >
  49. <el-button
  50. type="text"
  51. icon="el-icon-view"
  52. size="small"
  53. @click.stop="viewInfo(scope.row, scope.index)"
  54. >模版信息
  55. </el-button>
  56. <el-button
  57. type="text"
  58. icon="el-icon-s-operation"
  59. size="small"
  60. @click.stop="handleAdd(scope.row, scope.index)"
  61. >清表模版
  62. </el-button>
  63. <el-button
  64. type="text"
  65. icon="el-icon-s-opportunity"
  66. size="small"
  67. @click.stop="ElementIdentification(scope.row, scope.index)"
  68. >元素识别
  69. </el-button>
  70. </template>
  71. <template
  72. slot-scope="{row}"
  73. slot="source"
  74. >
  75. <div style="text-align:center">
  76. <i :class="row.source" />
  77. </div>
  78. </template>
  79. <template
  80. slot-scope="{row}"
  81. slot="tabType"
  82. >
  83. <el-tag
  84. size="small"
  85. v-for="item in generateTagItems(row.tabType)"
  86. :key="item.label"
  87. :type="item.type"
  88. effect="dark"
  89. class="mr-3 custom-ellipse-tag"
  90. :class="`custom-tag-type-${item.type}`"
  91. >
  92. {{ item.label }}
  93. </el-tag>
  94. </template>
  95. <template slot-scope="{row}" slot="projectInfoList">
  96. <el-tooltip
  97. v-for="item in row.projectInfoList"
  98. :key="item.id"
  99. :content="item.projectName"
  100. placement="top"
  101. :disabled="item.projectName.length<20"
  102. >
  103. <el-tag
  104. size="small"
  105. type="info"
  106. class="custom-ellipse-tag1 ellipsis-tag"
  107. >
  108. {{item.projectName}}
  109. </el-tag>
  110. </el-tooltip>
  111. </template>
  112. </avue-crud>
  113. <!-- 模板信息 -->
  114. <el-dialog
  115. class="project-dialog"
  116. :visible.sync="infoVisible"
  117. width="65%"
  118. append-to-body
  119. >
  120. <span slot="title">
  121. <i class="el-icon-view" style="color: #2550A2; margin-right: 10px;"></i>模板信息
  122. </span>
  123. <div class="dialog-content" v-loading="infoLoading">
  124. <!-- 模板基本信息 -->
  125. <div class="basic-info">
  126. <div class="flex">
  127. <div class="info-row">
  128. <el-tag
  129. size="small"
  130. v-for="item in generateTagItems(templateInfo.tabType)"
  131. :key="item.label"
  132. :type="item.type"
  133. effect="dark"
  134. class="mr-3 custom-ellipse-tag"
  135. :class="`custom-tag-type-${item.type}`"
  136. >
  137. {{ item.label }}
  138. </el-tag>
  139. </div>
  140. <div class="info-row ml-4">
  141. <div class="pro-label">{{ templateInfo.name }}</div>
  142. <div >{{ templateInfo.tableTemplateTypeName||'项目类型' }}</div>
  143. <div class="value">
  144. <span> 创建信息:</span>
  145. <span>{{ templateInfo.createUserName }}</span>
  146. <span class="ml-4">{{templateInfo.createTime }}</span>
  147. </div>
  148. </div>
  149. </div>
  150. <div class="flex info-row-right">
  151. <div class="info-row">
  152. <div class="value-num">{{ templateInfo.projectUseNumber||0 }}</div>
  153. <div class="label">使用项目数</div>
  154. </div>
  155. <div class="info-row">
  156. <span class="value-num">{{ templateInfo.tabCout||0 }}</span>
  157. <span class="label">清表数量</span>
  158. </div>
  159. <div class="info-row">
  160. <span class="value-num">{{ templateInfo.excelUseNumber||0 }}</span>
  161. <span class="label">清表使用数量</span>
  162. </div>
  163. </div>
  164. </div>
  165. <!-- 使用项目明细 -->
  166. <div class="section-title">使用项目明细</div>
  167. <div class="project-tags" v-if="templateInfo.projectInfoList">
  168. <el-tag
  169. v-for="item in templateInfo.projectInfoList"
  170. :key="item.id"
  171. size="small"
  172. type="info"
  173. class="custom-ellipse-tag1 ellipsis-tag4"
  174. >
  175. {{ item.projectName }}
  176. </el-tag>
  177. </div>
  178. <div v-else>暂无数据</div>
  179. <!-- 模板操作信息 -->
  180. <div class="section-title" v-if="false">模板操作信息</div>
  181. <el-table
  182. v-if="false"
  183. :data="templateInfo.operationLogs"
  184. border
  185. style="width: 100%; margin-top: 10px;"
  186. :header-cell-style="{ background: '#f5f7fa', color: '#666' }"
  187. >
  188. <el-table-column prop="index" label="序号" width="60" align="center">
  189. <template slot-scope="scope">
  190. {{ scope.$index + 1 }}
  191. </template>
  192. </el-table-column>
  193. <el-table-column prop="operationDesc" label="操作描述" min-width="200">
  194. <template slot-scope="scope">
  195. <span>{{ scope.row.operationDesc }}</span>
  196. </template>
  197. </el-table-column>
  198. <el-table-column prop="operator" label="操作人" width="100">
  199. <template slot-scope="scope">
  200. {{ scope.row.operator }}
  201. </template>
  202. </el-table-column>
  203. <el-table-column prop="operateTime" label="操作时间" width="180">
  204. <template slot-scope="scope">
  205. {{ scope.row.operateTime }}
  206. </template>
  207. </el-table-column>
  208. </el-table>
  209. <!-- 分页 -->
  210. <div class="pagination-container" v-if="templateInfo.total > 0">
  211. <el-pagination
  212. @size-change="handleSizeChange"
  213. @current-change="handleCurrentChange"
  214. :current-page="currentPage"
  215. :page-sizes="[10, 20, 30, 40]"
  216. :page-size="pageSize"
  217. layout="total, sizes, prev, pager, next, jumper"
  218. :total="templateInfo.total"
  219. />
  220. </div>
  221. </div>
  222. </el-dialog>
  223. <!-- 排序 -->
  224. <!-- wbs排序弹窗 -->
  225. <ContractSort
  226. ref="contractSortRef"
  227. title="清表模板排序"
  228. :sortProLoad="sortProLoad"
  229. @confirm="handleSortConfirm"
  230. />
  231. </basic-container>
  232. </template>
  233. <script>
  234. import { getList, getDetail, add, update, remove,getExcelInfo } from "@/api/exctab/exceltab";
  235. import { exctabSort } from "@/api/exctab/excelmodel";
  236. import { mapGetters } from "vuex";
  237. import { getDictionary } from "@/api/system/dict";
  238. import { getProjectListPage } from "@/api/manager/projectinfo";
  239. import { getDictionaryBiz } from "@/api/other";
  240. import ContractSort from './ContractSort.vue'
  241. export default {
  242. components: {
  243. ContractSort
  244. },
  245. data () {
  246. return {
  247. form: {},
  248. query: {},
  249. loading: true,
  250. page: {
  251. pageSize: 20,
  252. currentPage: 1,
  253. total: 0
  254. },
  255. search:{
  256. projectId: '',
  257. name: '',
  258. tabType: '',
  259. tableTemplateType:''
  260. },
  261. selectionList: [],
  262. option: {
  263. height: 'auto',
  264. calcHeight: 30,
  265. tip: false,
  266. searchShow: false,
  267. refreshBtn:false,
  268. searchShowBtn: false,
  269. columnBtn: false,
  270. border: true,
  271. index: true,
  272. viewBtn: false,
  273. addBtn: false,
  274. selection: true,
  275. menuWidth: 400,
  276. dialogClickModal: false,
  277. column: [
  278. {
  279. label: '创建时间',
  280. prop: 'createTime',
  281. width: 150,
  282. editDisplay: false,
  283. addDisplay: false,
  284. },
  285. {
  286. label: "模版名称",
  287. prop: "name",
  288. search: true,
  289. rules: [{
  290. required: true,
  291. message: "请输入名称",
  292. trigger: "blur"
  293. }]
  294. },
  295. {
  296. label: "项目类型",
  297. type: "select",
  298. width: 100,
  299. search: true,
  300. dicUrl: "/api/blade-system/dict-biz/dictionary?code=table_template_type",
  301. props: {
  302. label: "dictValue",
  303. value: "dictKey"
  304. },
  305. dataType: "number",
  306. prop: "tableTemplateType",
  307. rules: [{
  308. required: true,
  309. message: "请选择项目类型",
  310. trigger: "blur"
  311. }]
  312. },
  313. {
  314. label: "模板类型",
  315. type: "select",
  316. width: 120,
  317. slot: true,
  318. search: true,
  319. dicUrl: "/api/blade-system/dict/dictionary?code=wbs_type",
  320. props: {
  321. label: "dictValue",
  322. value: "dictKey"
  323. },
  324. dataType: "number",
  325. prop: "tabType",
  326. rules: [{
  327. required: true,
  328. message: "请选择项目类型",
  329. trigger: "blur"
  330. }]
  331. },
  332. {
  333. label: "表数量",
  334. prop: "tabCout",
  335. width: 80,
  336. editDisplay: false,
  337. addDisplay: false,
  338. rules: [{
  339. message: "请输入表数量",
  340. trigger: "blur",
  341. }]
  342. },
  343. {
  344. label: "项目名称",
  345. prop: "projectInfoList",
  346. display: false,
  347. search: true,
  348. slot:true,
  349. },
  350. ]
  351. },
  352. data: [],
  353. tableTemplateTypeList: [],
  354. projectList:[],
  355. infoVisible: false,
  356. infoLoading: false,
  357. templateInfo: {
  358. },
  359. currentPage: 1,
  360. pageSize: 20,
  361. tabTypeList:[],
  362. sortList : [],
  363. sortListAll:[],
  364. sortProLoad:false
  365. };
  366. },
  367. computed: {
  368. ...mapGetters(["permission"]),
  369. permissionList () {
  370. return {
  371. addBtn: this.vaildData(this.permission.exceltab_add, false),
  372. viewBtn: this.vaildData(this.permission.exceltab_view, false),
  373. delBtn: this.vaildData(this.permission.exceltab_delete, false),
  374. editBtn: this.vaildData(this.permission.exceltab_edit, false)
  375. };
  376. },
  377. ids () {
  378. let ids = [];
  379. this.selectionList.forEach(ele => {
  380. ids.push(ele.id);
  381. });
  382. return ids.join(",");
  383. }
  384. },
  385. methods: {
  386. getTableTemplateTypeList(){
  387. let code = "table_template_type";
  388. getDictionaryBiz({
  389. code,
  390. }).then((res) => {
  391. this.tableTemplateTypeList = res.data.data;
  392. });
  393. },
  394. getTabTypeList(){
  395. let code = "wbs_type";
  396. getDictionary({
  397. code,
  398. }).then((res) => {
  399. this.tabTypeList = res.data.data;
  400. });
  401. },
  402. getProjectList() {
  403. let params = {};
  404. params.page = this.currentPage;
  405. params.size = this.pageSize;
  406. getProjectListPage({
  407. size:999,
  408. current:1,
  409. isCollect:0,
  410. }).then((res) => {
  411. this.projectList = res.data.data.records;
  412. });
  413. },
  414. onLoad (page, params = {}) {
  415. this.loading = true;
  416. },
  417. generateTagItems(wbsTypes){
  418. const typeToLabelMap = {
  419. 1: '质检',
  420. 2: '试验',
  421. 3: '计量',
  422. 4: '日志',
  423. 5: '征拆',
  424. 6: '底层节点',
  425. };
  426. let tagItems = [];
  427. // 如果 wbsTypes 不是数组,则将其转换为数组
  428. if (!Array.isArray(wbsTypes)) {
  429. wbsTypes = [wbsTypes];
  430. }
  431. wbsTypes.forEach(type => {
  432. // 检查type是否在映射关系中存在
  433. if (typeToLabelMap.hasOwnProperty(type)) {
  434. // 如果存在,则创建一个新的对象并添加到tagItems数组中
  435. tagItems.push({
  436. type: type,
  437. label: typeToLabelMap[type]
  438. });
  439. }
  440. });
  441. return tagItems;
  442. },
  443. handleAdd (row) {
  444. this.$router.push('/excel/excelmodel/' + row.id);
  445. },
  446. ElementIdentification (row) {
  447. this.$router.push('/excels/ElementIdentification/' + row.id);
  448. },
  449. rowSave (row, done, loading) {
  450. add(row).then(() => {
  451. this.onLoad(this.page);
  452. this.$message({
  453. type: "success",
  454. message: "操作成功!"
  455. });
  456. done();
  457. }, error => {
  458. loading();
  459. window.console.log(error);
  460. });
  461. },
  462. rowUpdate (row, index, done, loading) {
  463. update(row).then(() => {
  464. this.onLoad(this.page);
  465. this.$message({
  466. type: "success",
  467. message: "操作成功!"
  468. });
  469. done();
  470. }, error => {
  471. loading();
  472. console.log(error);
  473. });
  474. },
  475. rowDel (row) {
  476. this.$confirm("删除后,数据无法恢复,是否确认删除?", {
  477. confirmButtonText: "确定",
  478. cancelButtonText: "取消",
  479. type: "warning"
  480. })
  481. .then(() => {
  482. return remove(row.id);
  483. })
  484. .then(() => {
  485. this.onLoad(this.page);
  486. this.$message({
  487. type: "success",
  488. message: "操作成功!"
  489. });
  490. });
  491. },
  492. handleDelete () {
  493. if (this.selectionList.length === 0) {
  494. this.$message.warning("请选择至少一条数据");
  495. return;
  496. }
  497. this.$confirm("确定将选择数据删除?", {
  498. confirmButtonText: "确定",
  499. cancelButtonText: "取消",
  500. type: "warning"
  501. })
  502. .then(() => {
  503. return remove(this.ids);
  504. })
  505. .then(() => {
  506. this.onLoad(this.page);
  507. this.$message({
  508. type: "success",
  509. message: "操作成功!"
  510. });
  511. this.$refs.crud.toggleSelection();
  512. });
  513. },
  514. beforeOpen (done, type) {
  515. if (["edit", "view"].includes(type)) {
  516. getDetail(this.form.id).then(res => {
  517. this.form = res.data.data;
  518. });
  519. }
  520. done();
  521. },
  522. searchReset () {
  523. this.query = {};
  524. this.onLoad(this.page);
  525. },
  526. searchChange (params, done) {
  527. this.query = params;
  528. this.page.currentPage = 1;
  529. this.onLoad(this.page, params);
  530. done();
  531. },
  532. selectionChange (list) {
  533. this.selectionList = list;
  534. },
  535. selectionClear () {
  536. this.selectionList = [];
  537. this.$refs.crud.toggleSelection();
  538. },
  539. currentChange (currentPage) {
  540. this.page.currentPage = currentPage;
  541. },
  542. sizeChange (pageSize) {
  543. this.page.pageSize = pageSize;
  544. },
  545. refreshChange () {
  546. this.onLoad(this.page, this.query);
  547. },
  548. onLoad (page, params = {}) {
  549. console.log(page.currentPage, params.pageSize);
  550. this.query.parentId = 0;
  551. this.loading = true;
  552. getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
  553. const data = res.data.data;
  554. this.page.total = data.total;
  555. this.data = data.records;
  556. this.loading = false;
  557. this.selectionClear();
  558. });
  559. },
  560. //查看模板信息
  561. viewInfo(row,index){
  562. this.infoVisible = true;
  563. this.getExcelInfoData(row.id)
  564. },
  565. handleSizeChange(val) {
  566. this.pageSize = val;
  567. this.currentPage = 1;
  568. // 可重新请求数据
  569. },
  570. handleCurrentChange(val) {
  571. this.currentPage = val;
  572. // 可重新请求数据
  573. },
  574. getExcelInfoData(id){
  575. this.infoLoading = true;
  576. getExcelInfo({id:id}).then((res) => {
  577. if(res.data.code==200){
  578. this.templateInfo = res.data.data;
  579. }else{
  580. this.templateInfo = {}
  581. }
  582. }).finally(() => {
  583. this.infoLoading = false;
  584. });
  585. },
  586. searchClick(){
  587. this.onLoad(this.page,this.query);
  588. },
  589. clearSearch () {
  590. this.query = {}
  591. this.onLoad(this.page,this.query);
  592. },
  593. addClick(){
  594. this.$refs.crud.rowAdd();
  595. },
  596. //排序
  597. handleSort(){
  598. this.sortProLoad = true;
  599. getList(1, 1000,{parentId:0}).then(res => {
  600. const data = res.data.data;
  601. this.sortListAll = data.records;
  602. this.sortList = JSON.parse(JSON.stringify(this.sortListAll));
  603. this.$nextTick(() => {
  604. this.$refs.contractSortRef.show(this.sortList);
  605. })
  606. }).finally(()=>{
  607. this.sortProLoad = false;
  608. })
  609. },
  610. handleSortConfirm(sortedList) {
  611. // 这里处理排序后的数据
  612. console.log('排序后的列表:', sortedList);
  613. // TODO: 调用接口保存排序结果
  614. this.sortList = [...sortedList];
  615. const ids = this.sortList.map(item => item.id);
  616. this.saveSort(ids);
  617. },
  618. saveSort(ids){
  619. let allIds=ids.join(',');
  620. exctabSort({ids:allIds}).then((res) => {
  621. this.sortProLoad= false;
  622. if(res.data.code==200){
  623. this.$message.success(res.data.msg)
  624. this.onLoad(this.page);
  625. }else{
  626. this.$message.error(res.data.msg)
  627. }
  628. })
  629. }
  630. },
  631. created() {
  632. this.getTableTemplateTypeList()
  633. this.getProjectList()
  634. this.getTabTypeList()
  635. },
  636. };
  637. </script>
  638. <style scoped lang="scss">
  639. .ellipsis-tag {
  640. max-width:300px; /* 设置最大宽度 */
  641. overflow: hidden;
  642. margin-right: 4px;
  643. .el-tag__content {
  644. display: inline-block;
  645. max-width: 100%;
  646. overflow: hidden;
  647. text-overflow: ellipsis;
  648. white-space: nowrap;
  649. }
  650. }
  651. .ellipsis-tag4 {
  652. overflow: hidden;
  653. margin-right: 4px;
  654. .el-tag__content {
  655. display: inline-block;
  656. max-width: 100%;
  657. overflow: hidden;
  658. text-overflow: ellipsis;
  659. white-space: nowrap;
  660. }
  661. }
  662. .dialog-content {
  663. padding: 20px;
  664. font-size: 14px;
  665. .basic-info {
  666. margin-bottom: 20px;
  667. display: flex;
  668. justify-content: space-between;
  669. align-items: center;
  670. .info-row-right{
  671. line-height: 30px;
  672. }
  673. .info-row {
  674. display: flex;
  675. flex-direction:column ;
  676. margin-bottom: 10px;
  677. .label {
  678. width: 100px;
  679. color: #666;
  680. text-align: center;
  681. }
  682. .pro-label{
  683. font-weight: bold;
  684. font-size: larger;
  685. }
  686. .value {
  687. flex: 1;
  688. }
  689. .value-num{
  690. font-size: larger;
  691. font-weight: bold;
  692. color: rgba(37, 80, 162, 1);
  693. text-align: center;
  694. }
  695. }
  696. }
  697. .section-title {
  698. font-weight: bold;
  699. margin: 15px 0 10px;
  700. background-color: #E0E0E0;
  701. font-size: larger;
  702. padding-left: 15px;
  703. padding: 5px 0 5px 15px;
  704. line-height: 30px;
  705. color: rgba(118, 118, 118, 1);
  706. border-radius: 5px;
  707. }
  708. .project-tags {
  709. display: flex;
  710. flex-wrap: wrap;
  711. gap: 8px;
  712. margin-bottom: 20px;
  713. }
  714. .pagination-container {
  715. margin-top: 20px;
  716. text-align: center;
  717. }
  718. }
  719. .ml-4{
  720. margin-left: 4px;
  721. }
  722. .filter-item{
  723. margin-right: 10px;
  724. }
  725. .search-box{
  726. display: flex;
  727. justify-content: space-between;
  728. }
  729. </style>