index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <template>
  2. <div class="my-container">
  3. <div class="bill-left">
  4. <div class="bill-tab">
  5. <div class="title">导航</div>
  6. <el-tree :data="data" :props="props" @node-click="handleNodeClick"></el-tree>
  7. </div>
  8. </div>
  9. <div class="bill-main">
  10. <div v-show="!hideSearch">
  11. <by-form :propConfig="config" ref="formId" />
  12. <div class="search-btn">
  13. <el-button type="primary" size="mini" icon="el-icon-search" @click="searchHandle">搜索</el-button>
  14. <el-button size="mini" icon="el-icon-refresh" @click="resertHandle">重置</el-button>
  15. </div>
  16. </div>
  17. <by-tool :propConfig="toolConfig" ref="toolId" @clickHandle="clickHandle" />
  18. <el-table :data="tableData" v-loading="loading" style="width: 100%;margin: 20px 0;" :show-overflow-tooltip="true"
  19. row-key="id" ref="tableId" :tree-props="{children: 'children'}" @cell-click="doClick">
  20. <!-- <el-table-column type="selection" width="55" /> -->
  21. <el-table-column prop="name" label="名称" width="200" @click="clickMy" />
  22. <el-table-column prop="shortName" label="简称" width="200" />
  23. <el-table-column prop="status" label="状态">
  24. <template slot-scope="scope">
  25. <el-tag :type="scope.row.status===0?'primary':'danger'"
  26. disable-transitions>{{scope.row.status===0?'正常':'禁用'}}</el-tag>
  27. </template>
  28. </el-table-column>
  29. <el-table-column prop="remark" label="备注" />
  30. <el-table-column label="操作" width="100" style="text-align: center;">
  31. <template>
  32. <el-button type="text" size="small" icon="el-icon-edit" @click="dialogEdit">编辑</el-button>
  33. <el-button type="text" size="small" @click="doDelete">删除</el-button>
  34. </template>
  35. </el-table-column>
  36. </el-table>
  37. <!-- 新增/编辑弹窗 -->
  38. <el-dialog :title="title+'分类'" :visible.sync="dialogFormVisible" width="30%">
  39. <by-form :propConfig="addConfig" ref="addFormId" style="height:250px;">
  40. <!-- <template v-slot:uploadImg>
  41. <div class="upload-img">+</div>
  42. </template> -->
  43. <template v-slot:status class="clearfix">
  44. <el-radio class="fl" style="margin-top: 8px;" v-model="radio" label="0">显示</el-radio>
  45. <el-radio class="fl" style="margin-top: 8px;" v-model="radio" label="1">禁用</el-radio>
  46. </template>
  47. <template v-slot:category>
  48. <el-cascader style="width: 100%;" v-model="cascaderValue" :options="options" :props="props"
  49. :show-all-levels="false" clearable @change="getChange" />
  50. </template>
  51. </by-form>
  52. <div slot="footer" class="dialog-footer">
  53. <el-button @click="dialogFormVisible = false">取 消</el-button>
  54. <el-button type="primary" @click="confirm">确 定</el-button>
  55. </div>
  56. </el-dialog>
  57. </div>
  58. </div>
  59. </template>
  60. <script lang="ts">
  61. import { Component, Prop, Vue, Watch } from "vue-property-decorator";
  62. import api from "@/api/materialClass";
  63. @Component({})
  64. export default class ProductClassification extends Vue {
  65. hideSearch = false
  66. title = '新增'
  67. loading : boolean = true
  68. dialogFormVisible : boolean = false
  69. cellsData : any = ''
  70. cascaderValue : any = ''
  71. radio = '0'
  72. data : any = []
  73. props = {
  74. label: 'name',
  75. value: 'id',
  76. children: 'children',
  77. checkStrictly: true
  78. }
  79. options : Array<any> = []
  80. tableData : Array<any> = []
  81. toolConfig = {
  82. tools: {
  83. add: true,
  84. export: true,
  85. search: true,
  86. refresh: true
  87. },
  88. audit: {
  89. add: 'audit:collaborationLog:add',
  90. export: 'audit:collaborationLog:export'
  91. }
  92. }
  93. config = {
  94. attr: {
  95. size: 'small',
  96. height: 40
  97. },
  98. columns: [
  99. [{
  100. span: 6,
  101. label: '名称',
  102. prop: 'name',
  103. component: 'by-input',
  104. labelWidth: '70px',
  105. compConfig: {
  106. attr: {
  107. placeholder: '请输入名称',
  108. clearable: true
  109. }
  110. },
  111. }, {
  112. span: 6,
  113. label: '简称',
  114. prop: 'shortName',
  115. component: 'by-input',
  116. labelWidth: '70px',
  117. compConfig: {
  118. attr: {
  119. placeholder: '请输入简称',
  120. clearable: true
  121. }
  122. }
  123. },
  124. {
  125. span: 6,
  126. label: '状态',
  127. prop: 'status',
  128. component: 'by-input',
  129. labelWidth: '70px',
  130. compConfig: {
  131. attr: {
  132. placeholder: '请输入状态',
  133. clearable: true
  134. }
  135. }
  136. },
  137. {
  138. span: 6,
  139. label: '备注',
  140. prop: 'remark',
  141. component: 'by-input',
  142. labelWidth: '70px',
  143. compConfig: {
  144. attr: {
  145. placeholder: '请输入状态',
  146. clearable: true
  147. }
  148. }
  149. },
  150. ]
  151. ]
  152. }
  153. addConfig = {
  154. attr: {
  155. size: 'small',
  156. height: 60
  157. },
  158. columns: [
  159. [
  160. {
  161. labelWidth: '80px',
  162. span: 20,
  163. label: '上级分类',
  164. slot: true,
  165. prop: 'category',
  166. },
  167. {
  168. span: 20,
  169. label: '分类名称',
  170. prop: 'name',
  171. component: 'by-input',
  172. labelWidth: '80px',
  173. },
  174. {
  175. span: 20,
  176. label: '简称',
  177. prop: 'shortName',
  178. component: 'by-input',
  179. labelWidth: '80px',
  180. },
  181. {
  182. span: 20,
  183. label: '显示状态',
  184. slot: true,
  185. prop: 'status',
  186. },
  187. {
  188. span: 20,
  189. label: '备注',
  190. prop: 'remark',
  191. component: 'by-input',
  192. labelWidth: '80px',
  193. },]
  194. ]
  195. }
  196. created() {
  197. this.getDataList()
  198. }
  199. clickMy(e:any){
  200. console.log(e);
  201. }
  202. // 获取列表数据
  203. getDataList() {
  204. api.treeList().then((res : any) => {
  205. // console.log(res.data[0]);
  206. if (res.code === 200) {
  207. this.tableData = res.data[0].children;
  208. this.data = res.data[0].children;
  209. let arr : any = [{
  210. name: '顶级',
  211. id: 0,
  212. children: res.data
  213. }]
  214. this.options = arr;
  215. this.loading = false;
  216. } else this.failHandle(res)
  217. })
  218. }
  219. // 工具栏方法
  220. clickHandle(e : any) {
  221. console.log('工具栏方法 ==> ', e);
  222. if (e === 'toggleSearch') this.toggleSearch();
  223. if (e === 'onRefresh') this.onRefresh();
  224. if (e === 'onExport') this.onExport();
  225. if (e === 'onAdd') this.onAdd();
  226. }
  227. // 单元格点击
  228. doClick(e : any) {
  229. console.log('单元格点击 ==> ', e);
  230. this.cellsData = e;
  231. this.radio = e.status.toString();
  232. if ((this as any).$refs.addFormId) (this as any).$refs.addFormId.setValue(e);
  233. }
  234. // 新增
  235. onAdd() {
  236. this.title = '新增';
  237. this.radio = '0';
  238. this.cascaderValue = [0];
  239. setTimeout(() => {
  240. if ((this as any).$refs.addFormId) (this as any).$refs.addFormId.setValue({});
  241. this.dialogFormVisible = true;
  242. }, 0)
  243. }
  244. // 编辑
  245. dialogEdit() {
  246. this.title = '编辑';
  247. this.cascaderValue = [0];
  248. this.dialogFormVisible = true;
  249. }
  250. // 获取选择节点
  251. getChange(e : any) {
  252. console.log('获取选择节点 ==> ', e);
  253. // this.cascaderValue = e;
  254. }
  255. // 确认新增/编辑
  256. confirm() {
  257. let query = (this as any).$refs.addFormId.getValue();
  258. let pareteId : any = this.cascaderValue[this.cascaderValue.length - 1];
  259. if (pareteId !== 0) if (!this.cascaderValue[this.cascaderValue.length - 1]) return this.$message({
  260. type: 'error',
  261. message: '请输入完整字段'
  262. })
  263. if (query.name?.length > 0 && query.shortName?.length > 0 && query.remark?.length > 0) {
  264. // console.log(pareteId, this.radio);
  265. this.dialogFormVisible = false;
  266. if (this.title === '新增') {
  267. api.saveCategory({
  268. name: query.name,
  269. shortName: query.shortName,
  270. status: this.radio,
  271. remark: query.remark,
  272. parentId: pareteId// 父级id
  273. }).then((res : any) => {
  274. if (res.code === 200) {
  275. this.$message({
  276. type: 'success',
  277. message: this.title + '成功!'
  278. });
  279. this.getDataList();
  280. } else this.failHandle(res)
  281. })
  282. } else if (this.title === '编辑') {
  283. api.updateCategory({
  284. id: this.cellsData.id,
  285. name: query.name,
  286. shortName: query.shortName,
  287. status: this.radio,
  288. remark: query.remark,
  289. parentId: pareteId // 父级id
  290. }).then((res : any) => {
  291. if (res.code === 200) {
  292. this.$message({
  293. type: 'success',
  294. message: this.title + '成功!'
  295. });
  296. this.getDataList();
  297. } else this.failHandle(res)
  298. })
  299. }
  300. } else this.$message({
  301. type: 'error',
  302. message: '请输入完整字段'
  303. })
  304. }
  305. // 删除
  306. doDelete() {
  307. setTimeout(() => {
  308. if (this.cellsData.children.length > 0) return this.$message({
  309. type: 'error',
  310. message: '此节点还有子集,不能做此操作'
  311. });
  312. this.$confirm('确定删除吗,此操作不能撤销!', '提示', {
  313. confirmButtonText: '确定',
  314. cancelButtonText: '取消',
  315. type: 'warning',
  316. center: true
  317. }).then(() => {
  318. api.classDelete({
  319. ids: this.cellsData.id
  320. }).then((res : any) => {
  321. if (res.code === 200) {
  322. this.getDataList();
  323. this.$message({
  324. type: 'success',
  325. message: '删除成功!'
  326. });
  327. }
  328. })
  329. }).catch(() => {
  330. this.$message({
  331. type: 'info',
  332. message: '已取消删除'
  333. });
  334. });
  335. }, 0)
  336. }
  337. // 导航切换
  338. handleNodeClick(e : any) {
  339. console.log('导航切换id ==> ',e.id);
  340. this.loading = true;
  341. api.childrenTreeList(e.id).then((res : any) => {
  342. if (res.code === 200) {
  343. this.tableData = res.data;
  344. this.loading = false;
  345. }
  346. })
  347. }
  348. //重置
  349. resertHandle() {
  350. this.loading = true;
  351. (this.$refs.formId as any).setValue({});
  352. // (this.$refs.tableId as any).setPage({ pageNo: 1, total: 0 });
  353. this.getDataList();
  354. }
  355. //刷新
  356. onRefresh() {
  357. this.loading = true;
  358. // (this.$refs.formId as any).setValue({});
  359. // (this.$refs.tableId as any).setPage({ pageNo: 1, total: 0 });
  360. this.getDataList();
  361. }
  362. // 搜索
  363. searchHandle() {
  364. this.loading = true;
  365. let query : any = (this.$refs.formId as any).getValue();
  366. if (!query.name) return this.getDataList();
  367. api.searchTreeList({ name: query.name || query.shortName }).then((res : any) => {
  368. if (res.code === 200) {
  369. this.tableData = [];
  370. this.tableData = res.data.records;
  371. this.loading = false;
  372. };
  373. })
  374. }
  375. //获取查询值
  376. getQuery() {
  377. let query : any = (this.$refs.formId as any).getValue();
  378. // const page:any = (this.$refs.tableId as any).getPage();
  379. // query.pageNum = page.pageNo;
  380. // query.pageSize = page.pageSize;
  381. return query;
  382. }
  383. //导出
  384. onExport() {
  385. let urlArr = '/maindata/maindataMaterialOrganizationCategory';
  386. let query = this.getQuery();
  387. (this as any).$download(urlArr + '/export', {
  388. ...query
  389. }, urlArr[urlArr.length - 1] + `_${new Date().getTime()}.xlsx`)
  390. }
  391. //显示/隐藏搜索
  392. toggleSearch() {
  393. this.hideSearch = !this.hideSearch
  394. }
  395. // 运行错误
  396. failHandle(err : any) {
  397. let msg = err.msg ? err.msg : '运行错误!';
  398. this.$message.error(msg)
  399. }
  400. }
  401. </script>
  402. <style lang="scss">
  403. .my-container {
  404. .el-form-item__label {
  405. text-align: center;
  406. }
  407. .el-form-item__content {
  408. margin-right: 20px;
  409. }
  410. .has-gutter .is-leaf.el-table__cell:nth-of-type(5) {
  411. text-align: center;
  412. }
  413. .form-row.el-row>div {
  414. margin-bottom: 10px;
  415. }
  416. }
  417. .el-dialog:not(.is-fullscreen) {
  418. margin-top: 15vh !important;
  419. }
  420. .el-message-box {
  421. vertical-align: baseline;
  422. }
  423. </style>
  424. <style lang="scss" scoped>
  425. .my-container {
  426. width: 100%;
  427. box-sizing: border-box;
  428. display: flex;
  429. padding: 16px;
  430. .bill-left {
  431. position: relative;
  432. border-right: solid #EEE 1px;
  433. padding-right: 16px;
  434. flex-shrink: 0;
  435. // box-sizing: border-box;
  436. .bill-tab {
  437. width: 150px;
  438. height: 100%;
  439. transition: all .5s;
  440. overflow: hidden;
  441. }
  442. .title {
  443. font-size: 16px;
  444. padding-bottom: 16px;
  445. width: 200px;
  446. }
  447. .bill-nav {
  448. font-size: 14px;
  449. height: 30px;
  450. line-height: 30px;
  451. width: 200px;
  452. box-sizing: border-box;
  453. padding: 0 8px;
  454. cursor: pointer;
  455. margin-bottom: 2px;
  456. border-radius: 5px;
  457. }
  458. .onBill {
  459. background-color: #bde3f7;
  460. }
  461. .bill-nav:hover {
  462. background-color: #bde3f7;
  463. }
  464. .close {
  465. height: 22px;
  466. width: 22px;
  467. border-radius: 50%;
  468. border: solid #EEE 1px;
  469. position: absolute;
  470. top: 30px;
  471. right: -11px;
  472. background-color: #FFF;
  473. display: flex;
  474. justify-content: center;
  475. align-items: center;
  476. cursor: pointer;
  477. }
  478. }
  479. .bill-main {
  480. width: calc(100% - 16px);
  481. box-sizing: border-box;
  482. margin-left: 16px;
  483. position: relative;
  484. .upload-img {
  485. width: 150px;
  486. height: 150px;
  487. line-height: 150px;
  488. text-align: center;
  489. border-radius: 5px;
  490. background-color: #fbfdff;
  491. color: #8c939d;
  492. border: 1px dashed #c0ccda;
  493. font-size: 28px;
  494. }
  495. .upload-img:hover {
  496. border-color: #1890ff;
  497. }
  498. .search-btn {
  499. width: 100%;
  500. display: flex;
  501. justify-content: flex-end;
  502. margin-bottom: 20px;
  503. }
  504. .bill-box {
  505. width: 100%;
  506. position: absolute;
  507. left: 0;
  508. top: 0;
  509. opacity: 0;
  510. z-index: -1;
  511. transition: all .5s;
  512. .bill-tool,
  513. .table-tool {
  514. width: 100%;
  515. padding-bottom: 16px;
  516. }
  517. .form {
  518. margin-bottom: 8px;
  519. }
  520. }
  521. .on-show {
  522. opacity: 1;
  523. z-index: 1;
  524. }
  525. }
  526. }
  527. </style>