exceltab.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  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" con="el-icon-add" @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-tag"
  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. getProjectListPage() {
  403. let params = {};
  404. params.page = this.currentPage;
  405. params.size = this.pageSize;
  406. getProjectListPage(params).then((res) => {
  407. this.projectList = res.data.data.records;
  408. });
  409. },
  410. onLoad (page, params = {}) {
  411. this.loading = true;
  412. },
  413. generateTagItems(wbsTypes){
  414. const typeToLabelMap = {
  415. 1: '质检',
  416. 2: '试验',
  417. 3: '日志',
  418. 4: '计量',
  419. 5: '征拆',
  420. 6: '底层节点',
  421. };
  422. let tagItems = [];
  423. // 如果 wbsTypes 不是数组,则将其转换为数组
  424. if (!Array.isArray(wbsTypes)) {
  425. wbsTypes = [wbsTypes];
  426. }
  427. wbsTypes.forEach(type => {
  428. // 检查type是否在映射关系中存在
  429. if (typeToLabelMap.hasOwnProperty(type)) {
  430. // 如果存在,则创建一个新的对象并添加到tagItems数组中
  431. tagItems.push({
  432. type: type,
  433. label: typeToLabelMap[type]
  434. });
  435. }
  436. });
  437. return tagItems;
  438. },
  439. handleAdd (row) {
  440. this.$router.push('/excel/excelmodel/' + row.id);
  441. },
  442. ElementIdentification (row) {
  443. this.$router.push('/excels/ElementIdentification/' + row.id);
  444. },
  445. rowSave (row, done, loading) {
  446. add(row).then(() => {
  447. this.onLoad(this.page);
  448. this.$message({
  449. type: "success",
  450. message: "操作成功!"
  451. });
  452. done();
  453. }, error => {
  454. loading();
  455. window.console.log(error);
  456. });
  457. },
  458. rowUpdate (row, index, done, loading) {
  459. update(row).then(() => {
  460. this.onLoad(this.page);
  461. this.$message({
  462. type: "success",
  463. message: "操作成功!"
  464. });
  465. done();
  466. }, error => {
  467. loading();
  468. console.log(error);
  469. });
  470. },
  471. rowDel (row) {
  472. this.$confirm("确定将选择数据删除?", {
  473. confirmButtonText: "确定",
  474. cancelButtonText: "取消",
  475. type: "warning"
  476. })
  477. .then(() => {
  478. return remove(row.id);
  479. })
  480. .then(() => {
  481. this.onLoad(this.page);
  482. this.$message({
  483. type: "success",
  484. message: "操作成功!"
  485. });
  486. });
  487. },
  488. handleDelete () {
  489. if (this.selectionList.length === 0) {
  490. this.$message.warning("请选择至少一条数据");
  491. return;
  492. }
  493. this.$confirm("确定将选择数据删除?", {
  494. confirmButtonText: "确定",
  495. cancelButtonText: "取消",
  496. type: "warning"
  497. })
  498. .then(() => {
  499. return remove(this.ids);
  500. })
  501. .then(() => {
  502. this.onLoad(this.page);
  503. this.$message({
  504. type: "success",
  505. message: "操作成功!"
  506. });
  507. this.$refs.crud.toggleSelection();
  508. });
  509. },
  510. beforeOpen (done, type) {
  511. if (["edit", "view"].includes(type)) {
  512. getDetail(this.form.id).then(res => {
  513. this.form = res.data.data;
  514. });
  515. }
  516. done();
  517. },
  518. searchReset () {
  519. this.query = {};
  520. this.onLoad(this.page);
  521. },
  522. searchChange (params, done) {
  523. this.query = params;
  524. this.page.currentPage = 1;
  525. this.onLoad(this.page, params);
  526. done();
  527. },
  528. selectionChange (list) {
  529. this.selectionList = list;
  530. },
  531. selectionClear () {
  532. this.selectionList = [];
  533. this.$refs.crud.toggleSelection();
  534. },
  535. currentChange (currentPage) {
  536. this.page.currentPage = currentPage;
  537. },
  538. sizeChange (pageSize) {
  539. this.page.pageSize = pageSize;
  540. },
  541. refreshChange () {
  542. this.onLoad(this.page, this.query);
  543. },
  544. onLoad (page, params = {}) {
  545. console.log(page.currentPage, params.pageSize);
  546. this.query.parentId = 0;
  547. this.loading = true;
  548. getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
  549. const data = res.data.data;
  550. this.page.total = data.total;
  551. this.data = data.records;
  552. this.loading = false;
  553. this.selectionClear();
  554. });
  555. },
  556. getProjectList () {
  557. getProjectListPage({
  558. current:1,
  559. size:999,
  560. ...this.searchForm
  561. }).then((res) => {
  562. this.projectList = res.data.data.records;
  563. })
  564. },
  565. //查看模板信息
  566. viewInfo(row,index){
  567. this.infoVisible = true;
  568. this.getExcelInfoData(row.id)
  569. },
  570. handleSizeChange(val) {
  571. this.pageSize = val;
  572. this.currentPage = 1;
  573. // 可重新请求数据
  574. },
  575. handleCurrentChange(val) {
  576. this.currentPage = val;
  577. // 可重新请求数据
  578. },
  579. getExcelInfoData(id){
  580. this.infoLoading = true;
  581. getExcelInfo({id:id}).then((res) => {
  582. if(res.data.code==200){
  583. this.templateInfo = res.data.data;
  584. }else{
  585. this.templateInfo = {}
  586. }
  587. }).finally(() => {
  588. this.infoLoading = false;
  589. });
  590. },
  591. searchClick(){
  592. this.onLoad(this.page,this.query);
  593. },
  594. clearSearch () {
  595. this.query = {}
  596. this.onLoad(this.page,this.query);
  597. },
  598. addClick(){
  599. this.$refs.crud.rowAdd();
  600. },
  601. //排序
  602. handleSort(){
  603. this.sortProLoad = true;
  604. getList(1, 1000,{parentId:0}).then(res => {
  605. const data = res.data.data;
  606. this.sortListAll = data.records;
  607. this.sortList = JSON.parse(JSON.stringify(this.sortListAll));
  608. this.$nextTick(() => {
  609. this.$refs.contractSortRef.show(this.sortList);
  610. })
  611. }).finally(()=>{
  612. this.sortProLoad = false;
  613. })
  614. },
  615. handleSortConfirm(sortedList) {
  616. // 这里处理排序后的数据
  617. console.log('排序后的列表:', sortedList);
  618. // TODO: 调用接口保存排序结果
  619. this.sortList = [...sortedList];
  620. const ids = this.sortList.map(item => item.id);
  621. this.saveSort(ids);
  622. },
  623. saveSort(ids){
  624. let allIds=ids.join(',');
  625. exctabSort({ids:allIds}).then((res) => {
  626. this.sortProLoad= false;
  627. if(res.data.code==200){
  628. this.$message.success(res.data.msg)
  629. this.onLoad(this.page);
  630. }else{
  631. this.$message.error(res.data.msg)
  632. }
  633. })
  634. }
  635. },
  636. created() {
  637. this.getTableTemplateTypeList()
  638. this.getProjectList()
  639. this.getTabTypeList()
  640. },
  641. };
  642. </script>
  643. <style scoped lang="scss">
  644. .ellipsis-tag {
  645. max-width:300px; /* 设置最大宽度 */
  646. overflow: hidden;
  647. margin-right: 4px;
  648. .el-tag__content {
  649. display: inline-block;
  650. max-width: 100%;
  651. overflow: hidden;
  652. text-overflow: ellipsis;
  653. white-space: nowrap;
  654. }
  655. }
  656. .dialog-content {
  657. padding: 20px;
  658. font-size: 14px;
  659. .basic-info {
  660. margin-bottom: 20px;
  661. display: flex;
  662. justify-content: space-between;
  663. align-items: center;
  664. .info-row-right{
  665. line-height: 30px;
  666. }
  667. .info-row {
  668. display: flex;
  669. flex-direction:column ;
  670. margin-bottom: 10px;
  671. .label {
  672. width: 100px;
  673. color: #666;
  674. text-align: center;
  675. }
  676. .pro-label{
  677. font-weight: bold;
  678. font-size: larger;
  679. }
  680. .value {
  681. flex: 1;
  682. }
  683. .value-num{
  684. font-size: larger;
  685. font-weight: bold;
  686. color: rgba(37, 80, 162, 1);
  687. text-align: center;
  688. }
  689. }
  690. }
  691. .section-title {
  692. font-weight: bold;
  693. margin: 15px 0 10px;
  694. background-color: #E0E0E0;
  695. font-size: larger;
  696. padding-left: 15px;
  697. padding: 5px 0 5px 15px;
  698. line-height: 30px;
  699. color: rgba(118, 118, 118, 1);
  700. border-radius: 5px;
  701. }
  702. .project-tags {
  703. display: flex;
  704. flex-wrap: wrap;
  705. gap: 8px;
  706. margin-bottom: 20px;
  707. }
  708. .pagination-container {
  709. margin-top: 20px;
  710. text-align: center;
  711. }
  712. }
  713. .ml-4{
  714. margin-left: 4px;
  715. }
  716. .filter-item{
  717. margin-right: 10px;
  718. }
  719. .search-box{
  720. display: flex;
  721. justify-content: space-between;
  722. }
  723. </style>