index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. <template>
  2. <div>
  3. <basic-container v-show="show && showInfo" class="page-crad">
  4. <table border="0" width="100%" style="margin-bottom:20px;" v-loading="loading" :option="option">
  5. <tr>
  6. <td class="stat-td">
  7. <img src="@/assets/img/contractAmountBg.png" class="stat-img">
  8. <div class="stat-tip">
  9. <div class="money">
  10. <span style="font-size:20px;">¥</span>
  11. <avue-count-up :end="form.totalAmount"></avue-count-up>
  12. </div>
  13. <div class="title">合同金额</div>
  14. </div>
  15. </td>
  16. <!-- <td class="stat-td">
  17. <img src="@/assets/img/deliveredBg.png" class="stat-img">
  18. <div class="stat-tip">
  19. <div class="money">
  20. <span style="font-size:20px;">¥</span>
  21. <avue-count-up :end="form.deliveringAmount"></avue-count-up>
  22. </div>
  23. <div class="title">已送货</div>
  24. </div>
  25. </td>
  26. <td class="stat-td">
  27. <img src="@/assets/img/advanceCollectionBg.png" class="stat-img">
  28. <div class="stat-tip">
  29. <div class="money">
  30. <span style="font-size:20px;">¥</span>
  31. <avue-count-up :end="form.advancePayment"></avue-count-up>
  32. </div>
  33. <div class="title">预收款</div>
  34. <div class="title">(积累预收:)</div>
  35. </div>
  36. </td> -->
  37. <td class="stat-td">
  38. <img src="@/assets/img/uncollectedBg.png" class="stat-img">
  39. <div class="stat-tip">
  40. <div class="money">
  41. <span style="font-size:20px;">¥</span>
  42. <avue-count-up :end="form.paidAmount"></avue-count-up>
  43. </div>
  44. <div class="title">未收款</div>
  45. <!-- <div class="title">(积累欠款:)</div> -->
  46. </div>
  47. </td>
  48. <td class="stat-td">
  49. <img src="@/assets/img/receivableBg.png" class="stat-img">
  50. <div class="stat-tip">
  51. <div class="money">
  52. <span style="font-size:20px;">¥</span>
  53. <avue-count-up :end="form.unpaidAmount"></avue-count-up>
  54. </div>
  55. <div class="title">已收款</div>
  56. </div>
  57. </td>
  58. </tr>
  59. </table>
  60. <el-row>
  61. <el-col :span="4">
  62. <avue-tree :option="treeOption" :data="treeData" @node-click="nodeClick" style="height:73vh;"
  63. @save="corpTypeVisible = true">
  64. <template slot="addBtn">
  65. <i class="el-icon-setting" style="font-size:18px;line-height: 30px;width: 20px;padding: 0 10px;"
  66. @click="corpTypeVisible = true"></i>
  67. </template>
  68. </avue-tree>
  69. </el-col>
  70. <el-col :span="20">
  71. <avue-crud ref="crud" :option="option" :data="dataList" :page.sync="page" :search.sync="search"
  72. @search-change="searchChange" @current-change="currentChange" @size-change="sizeChange"
  73. @refresh-change="refreshChange" @on-load="onLoad" :table-loading="loading" @saveColumn="saveColumn"
  74. @resetColumn="resetColumn" :cell-style="cellStyle" @search-criteria-switch="searchCriteriaSwitch">
  75. <template slot="menuLeft">
  76. <!-- <el-button type="primary" size="mini" @click.stop="newAdd()">新建客户
  77. </el-button>
  78. <el-button type="primary" size="mini" icon="el-icon-bottom" @click="excelBox = true">导入
  79. </el-button> -->
  80. <el-button type="primary" size="mini" icon="el-icon-bottom" @click="outExport">导出
  81. </el-button>
  82. </template>
  83. <template slot-scope="{ row, index }" slot="cname">
  84. <span style="color: #409EFF;cursor: pointer" @click.stop="viewInfo(row)">{{ row.cname }}
  85. </span>
  86. </template>
  87. <template slot="idsSearch">
  88. <crop-select v-model="search.ids" corpType="KH"></crop-select>
  89. </template>
  90. <template slot="dateSearch">
  91. <el-date-picker v-model="search.date" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
  92. format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" :default-time="['00:00:00', '23:59:59']"
  93. :picker-options="pickerOptions">
  94. </el-date-picker>
  95. </template>
  96. <template slot-scope="{ row, index }" slot="menu">
  97. <el-tooltip class="item" effect="dark" content="编辑" placement="top">
  98. <i class="tradingIcon icon-edit" @click.stop="editOpen(row, 2)" />
  99. </el-tooltip>
  100. <el-tooltip class="item" effect="dark" content="收款" placement="top">
  101. <i class="tradingIcon icon-proceeds" />
  102. </el-tooltip>
  103. <el-tooltip class="item" effect="dark" content="发货" placement="top">
  104. <i class="tradingIcon icon-deliver" />
  105. </el-tooltip>
  106. <el-tooltip class="item" effect="dark" content="对账" placement="top">
  107. <i class="tradingIcon icon-reconciliation" />
  108. </el-tooltip>
  109. <el-tooltip class="item" effect="dark" content="删除" placement="top">
  110. <i class="tradingIcon icon-del" style="color: #FF0000" @click.stop="rowDel(row)" />
  111. </el-tooltip>
  112. <!-- <el-button type="text" size="small" @click.stop="editOpen(row, 2)">
  113. 查看
  114. </el-button>
  115. <el-button type="text" size="small" @click.stop="rowDel(row, index)">
  116. 删除
  117. </el-button> -->
  118. </template>
  119. </avue-crud>
  120. </el-col>
  121. </el-row>
  122. </basic-container>
  123. <details-page v-if="!show" @goBack="goBack()" :detailData="detailData" />
  124. <details-info v-if="!showInfo" @goBack="goBack()" @editOpen="editOpen" :detailData="detailData" />
  125. <el-dialog title="设置客户分类" v-dialogDrag :visible.sync="corpTypeVisible" class="avue-dialog" width="80%" append-to-body
  126. @closed="corpTypeClosed">
  127. <span>
  128. <corp-type></corp-type>
  129. <!-- <avue-form :key="reload" ref="corpType" v-model="form4" :option="option4" style="margin-top:20px">
  130. </avue-form> -->
  131. </span>
  132. <div class="avue-dialog__footer">
  133. <el-button @click="corpTypeVisible = false" size="mini">取 消</el-button>
  134. <el-button @click="addCorpType" type="primary" size="mini">确 定</el-button>
  135. </div>
  136. </el-dialog>
  137. <el-dialog title="导入客户" append-to-body :visible.sync="excelBox" width="555px" :close-on-click-modal="false"
  138. v-dialog-drag>
  139. <avue-form :option="excelOption" v-model="excelForm" table-loading="excelLoading" :upload-before="uploadBefore"
  140. :upload-after="uploadAfter">
  141. <template slot="excelTemplate">
  142. <el-button type="primary" @click="derivation">
  143. 点击下载<i class="el-icon-download el-icon--right"></i>
  144. </el-button>
  145. </template>
  146. </avue-form>
  147. <p style="text-align: center;color: #DC0505">
  148. 温馨提示 第一次导入时请先下载模板
  149. </p>
  150. </el-dialog>
  151. </div>
  152. </template>
  153. <script>
  154. import detailsInfo from "./detailsInfo";
  155. import detailsPage from "./detailsPage";
  156. import { option } from "./js/optionList";
  157. import {
  158. getCorpType,
  159. } from "@/api/tirePartsMall/basicData/customerInformation";
  160. import { getList, pageStatistics, remove, addCorpType, customerList } from "@/api/basicData/customerTransactions";
  161. import corpType from '@/components/corpType/index'
  162. import { getToken } from "@/util/auth";
  163. export default {
  164. name: "index",
  165. data() {
  166. return {
  167. corpTypeVisible: false,
  168. excelForm: {},
  169. excelOption: {
  170. submitBtn: false,
  171. emptyBtn: false,
  172. column: [
  173. {
  174. label: "模板下载",
  175. prop: "excelTemplate",
  176. formslot: true,
  177. span: 24
  178. },
  179. {
  180. label: "导入客户",
  181. prop: "excelFile",
  182. type: "upload",
  183. drag: true,
  184. loadText: "客户上传中,请稍等",
  185. accept: '.xls,.xlsx',
  186. span: 24,
  187. propsHttp: {
  188. res: "data"
  189. },
  190. tip: "请上传 .xls,.xlsx 标准格式文件",
  191. action: "/api/blade-client/partsCorps/import-desc"
  192. }
  193. ]
  194. },
  195. src: '',
  196. show: true,
  197. excelBox: false,
  198. showInfo: true,
  199. loading: false,
  200. search: {},
  201. detailData: {},
  202. dataList: [],
  203. selectionList: [],
  204. page: {
  205. pageSize: 20,
  206. currentPage: 1,
  207. total: 0,
  208. pageSizes: [10, 20, 30, 40, 50, 100, 200, 300, 400, 500]
  209. },
  210. form: {
  211. totalAmount: 0,
  212. paidAmount: 0,
  213. unpaidAmount: 0
  214. },
  215. formSerach: {},
  216. pickerOptions: {
  217. shortcuts: [
  218. {
  219. text: '当天',
  220. onClick(picker) {
  221. const date = new Date();
  222. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
  223. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  224. picker.$emit('pick', [start, end]);
  225. }
  226. },
  227. {
  228. text: '昨天',
  229. onClick(picker) {
  230. const date = new Date();
  231. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 0, 0, 0);
  232. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 23, 59, 59);
  233. picker.$emit('pick', [start, end]);
  234. }
  235. }, {
  236. text: '当月',
  237. onClick(picker) {
  238. const date = new Date();
  239. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  240. const end = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59);
  241. picker.$emit('pick', [start, end]);
  242. }
  243. }, {
  244. text: '当季',
  245. onClick(picker) {
  246. const date = new Date();
  247. const start = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3, 1, 0, 0, 0);
  248. const end = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3 + 3, 0, 23, 59, 59);
  249. picker.$emit('pick', [start, end]);
  250. }
  251. }, {
  252. text: '当年',
  253. onClick(picker) {
  254. const date = new Date();
  255. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  256. const end = new Date(date.getFullYear() + 1, 0, 0, 23, 59, 59);
  257. picker.$emit('pick', [start, end]);
  258. }
  259. }, {
  260. text: '最近一周',
  261. onClick(picker) {
  262. const date = new Date();
  263. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7, 0, 0, 0);
  264. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  265. picker.$emit('pick', [start, end]);
  266. }
  267. }, {
  268. text: '最近二周',
  269. onClick(picker) {
  270. const date = new Date();
  271. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 2, 0, 0, 0);
  272. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  273. picker.$emit('pick', [start, end]);
  274. }
  275. }, {
  276. text: '最近三周',
  277. onClick(picker) {
  278. const date = new Date();
  279. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 3, 0, 0, 0);
  280. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  281. picker.$emit('pick', [start, end]);
  282. }
  283. }]
  284. },
  285. treeOption: {
  286. addBtn: false,
  287. menu: false,
  288. size: "small",
  289. props: {
  290. labelText: "标题",
  291. label: "title",
  292. value: "value",
  293. }
  294. },
  295. treeData: [],
  296. form4: {},
  297. option4: {
  298. menuBtn: false,
  299. labelWidth: 80,
  300. column: [
  301. {
  302. label: "分类名称",
  303. prop: "cname",
  304. rules: [
  305. {
  306. required: true,
  307. message: "",
  308. trigger: "blur"
  309. }
  310. ],
  311. span: 24,
  312. },
  313. {
  314. label: "上级类型",
  315. prop: "parentId",
  316. dicData: [],
  317. type: "tree",
  318. props: {
  319. label: "cname",
  320. value: "id"
  321. },
  322. span: 24,
  323. }
  324. ]
  325. },
  326. hostUrl: '',
  327. option: {}
  328. };
  329. },
  330. components: {
  331. detailsPage,
  332. detailsInfo,
  333. corpType
  334. },
  335. async created() {
  336. this.option = await this.getColumnData(this.getColumnName(277.2), option);
  337. this.option.height = window.innerHeight - 330;
  338. this.getAllWorkDicts()
  339. this.findObject(this.option.column,'id').click = ()=>{
  340. this.$refs.crud.dicInit()
  341. }
  342. },
  343. activated() {
  344. this.$refs.crud.refreshTable();
  345. },
  346. methods: {
  347. derivation() {
  348. window.open(
  349. `/api/blade-client/partsCorps/export-template?${this.website.tokenHeader
  350. }=${getToken()}`
  351. );
  352. },
  353. //导出
  354. outExport() {
  355. let config = { params: { ...this.search } }
  356. if (config.params) {
  357. for (const propName of Object.keys(config.params)) {
  358. const value = config.params[propName];
  359. if (value !== null && typeof (value) !== "undefined") {
  360. if (value instanceof Array) {
  361. for (const key of Object.keys(value)) {
  362. let params = propName + '[' + key + ']';
  363. config.params[params] = value[key]
  364. }
  365. delete config.params[propName]
  366. }
  367. }
  368. }
  369. }
  370. const routeData = this.$router.resolve({
  371. path: '/api/blade-sales-part/statisticsCorp/export', //跳转目标窗口的地址
  372. query: {
  373. ...config.params, //括号内是要传递给新窗口的参数
  374. corpType:'GYS',
  375. identification: this.url
  376. }
  377. })
  378. window.open(routeData.href.slice(1, routeData.href.length) + '&' + `${this.website.tokenHeader}=${getToken()}`);
  379. },
  380. uploadBefore(file, done, loading) {
  381. done();
  382. loading = true;
  383. },
  384. uploadAfter(res, done, loading, column) {
  385. this.excelBox = false;
  386. let myError = res.toString();//转字符串
  387. myError = myError.replace("Error: ", "") // 去掉前面的" Error: "
  388. this.$message.success(myError);
  389. this.refreshChange();
  390. loading = false;
  391. done();
  392. },
  393. filterNode(value, data) {
  394. console.log(value, data)
  395. if (!value) return true;
  396. return data.label.indexOf(value) !== -1;
  397. },
  398. nodeClick(data) {
  399. this.search.corpsTypeId = data.value
  400. this.page.currentPage = 1;
  401. this.onLoad(this.page, this.search);
  402. },
  403. getAllWorkDicts() {
  404. //状态
  405. // this.getWorkDicts("client_status").then(res => {
  406. // this.findObject(this.option.column, "status").dicData = res.data.data;
  407. // });
  408. getCorpType({ corpType: 'GYS' }).then(res => {
  409. this.treeData = res.data.data
  410. });
  411. // customerList({ corpType: "KH" }).then(res => {
  412. // this.findObject(this.option4.column, "parentId").dicData = res.data.data.records
  413. // });
  414. this.$refs.crud.init();
  415. },
  416. searchCriteriaSwitch(type) {
  417. if (type) {
  418. this.option.height = this.option.height - 46;
  419. } else {
  420. this.option.height = this.option.height + 46;
  421. }
  422. this.$refs.crud.getTableHeight();
  423. },
  424. cellStyle() {
  425. return "padding:0;height:40px;";
  426. },
  427. //点击搜索按钮触发
  428. searchChange(params, done) {
  429. this.page.currentPage = 1;
  430. this.onLoad(this.page, params);
  431. done();
  432. },
  433. refreshChange() {
  434. this.onLoad(this.page, this.search);
  435. },
  436. newAdd() {
  437. this.show = false;
  438. },
  439. onLoad(page, params = {}) {
  440. let data = this.deepClone(Object.assign(params, this.search));
  441. if (data.date && data.date.length > 0) {
  442. data.startTime = data.date[0]
  443. data.endTime = data.date[1]
  444. }
  445. delete data.date
  446. data.corpType = "GYS"
  447. this.loading = true;
  448. getList(
  449. page.currentPage,
  450. page.pageSize,
  451. data
  452. )
  453. .then(res => {
  454. this.dataList = res.data.data.records ? res.data.data.records : [];
  455. this.page.total = res.data.data.total;
  456. })
  457. .finally(() => {
  458. pageStatistics(data).then(res => {
  459. this.form = res.data.data
  460. })
  461. this.loading = false;
  462. });
  463. },
  464. addCorpType() {
  465. // this.$refs["corpType"].validate((valid, done) => {
  466. // done();
  467. // if (valid) {
  468. // addCorpType({ ...this.form4, corpType: 'KH', status: 0 })
  469. // .then(res => {
  470. // this.$message.success("保存成功");
  471. // this.getAllWorkDicts()
  472. // this.corpTypeVisible = false
  473. // })
  474. // } else {
  475. // return false;
  476. // }
  477. // });
  478. this.getAllWorkDicts()
  479. this.corpTypeVisible = false
  480. },
  481. corpTypeClosed() {
  482. // this.reload = Math.random();
  483. // this.form4 = this.$options.data().form4
  484. },
  485. viewInfo(row) {
  486. this.show = true;
  487. this.detailData = {
  488. id: row.id,
  489. };
  490. this.showInfo = false;
  491. },
  492. editOpen(row, status) {
  493. this.showInfo = true;
  494. this.detailData = {
  495. id: row.id,
  496. status: status
  497. };
  498. this.show = false;
  499. },
  500. currentChange(val) {
  501. this.page.currentPage = val;
  502. },
  503. sizeChange(val) {
  504. this.page.currentPage = 1;
  505. this.page.pageSize = val;
  506. },
  507. rowDel(row, index, done) {
  508. this.$confirm("确定删除数据?", {
  509. confirmButtonText: "确定",
  510. cancelButtonText: "取消",
  511. type: "warning"
  512. }).then(() => {
  513. remove({ id: row.id, corpType: "KH" }).then(res => {
  514. if (res.data.code == 200) {
  515. this.$message({
  516. type: "success",
  517. message: "删除成功!"
  518. });
  519. this.onLoad(this.page, this.search);
  520. }
  521. });
  522. });
  523. },
  524. async saveColumn() {
  525. const inSave = await this.saveColumnData(
  526. this.getColumnName(277.2),
  527. this.option
  528. );
  529. if (inSave) {
  530. this.$nextTick(() => {
  531. this.$refs.crud.doLayout();
  532. });
  533. this.$message.success("保存成功");
  534. //关闭窗口
  535. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  536. }
  537. },
  538. async resetColumn() {
  539. this.option = option;
  540. const inSave = await this.delColumnData(this.getColumnName(277.2), option);
  541. if (inSave) {
  542. this.$nextTick(() => {
  543. this.$refs.crud.doLayout();
  544. });
  545. this.getAllWorkDicts()
  546. this.$message.success("重置成功");
  547. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  548. }
  549. },
  550. //返回列表
  551. goBack() {
  552. this.detailData = this.$options.data().detailData;
  553. this.show = true;
  554. this.showInfo = true;
  555. this.onLoad(this.page, this.search);
  556. this.$nextTick(() => {
  557. this.$refs.crud.doLayout();
  558. });
  559. },
  560. }
  561. }
  562. </script>
  563. <style lang="scss" scoped>
  564. .page-crad ::v-deep .basic-container__card {
  565. height: 94.2vh;
  566. }
  567. ::v-deep .el-form-item__error {
  568. display: none !important;
  569. }
  570. ::v-deep .el-input-group__append {
  571. padding: 0 0px !important;
  572. }
  573. .el-dialog ::v-deep .el-form-item__error {
  574. display: none !important;
  575. }
  576. .stat-td {
  577. text-align: center;
  578. position: relative;
  579. }
  580. .stat-img {
  581. width: 95%;
  582. height: 100px;
  583. }
  584. .stat-tip {
  585. position: absolute;
  586. left: 15px;
  587. top: 5px;
  588. .money {
  589. color: #fff;
  590. font-size: 28px;
  591. text-align: left;
  592. font-weight: 600;
  593. }
  594. .title {
  595. color: #fff;
  596. font-size: 14px;
  597. text-align: left;
  598. margin-top: 5px;
  599. margin-bottom: 0px;
  600. }
  601. }
  602. </style>