index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  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%"
  126. append-to-body @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"
  140. :upload-before="uploadBefore" :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. import {getUser} from "@/api/system/user";
  164. export default {
  165. name: "index",
  166. data() {
  167. return {
  168. corpTypeVisible: false,
  169. excelForm:{},
  170. excelOption: {
  171. submitBtn: false,
  172. emptyBtn: false,
  173. column: [
  174. {
  175. label: "模板下载",
  176. prop: "excelTemplate",
  177. formslot: true,
  178. span: 24
  179. },
  180. {
  181. label: "导入客户",
  182. prop: "excelFile",
  183. type: "upload",
  184. drag: true,
  185. loadText: "客户上传中,请稍等",
  186. accept:'.xls,.xlsx',
  187. span: 24,
  188. propsHttp: {
  189. res: "data"
  190. },
  191. tip: "请上传 .xls,.xlsx 标准格式文件",
  192. action: "/api/blade-client/partsCorps/import-desc"
  193. }
  194. ]
  195. },
  196. src: '',
  197. show: true,
  198. excelBox: false,
  199. showInfo: true,
  200. loading: false,
  201. search: {},
  202. detailData: {},
  203. dataList: [],
  204. selectionList: [],
  205. page: {
  206. pageSize: 20,
  207. currentPage: 1,
  208. total: 0,
  209. pageSizes: [10, 20, 30, 40, 50, 100, 200, 300, 400, 500]
  210. },
  211. form: {
  212. totalAmount: 0,
  213. paidAmount: 0,
  214. unpaidAmount: 0
  215. },
  216. formSerach: {},
  217. pickerOptions: {
  218. shortcuts: [
  219. {
  220. text: '当天',
  221. onClick(picker) {
  222. const date = new Date();
  223. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
  224. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  225. picker.$emit('pick', [start, end]);
  226. }
  227. },
  228. {
  229. text: '昨天',
  230. onClick(picker) {
  231. const date = new Date();
  232. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 0, 0, 0);
  233. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 23, 59, 59);
  234. picker.$emit('pick', [start, end]);
  235. }
  236. }, {
  237. text: '当月',
  238. onClick(picker) {
  239. const date = new Date();
  240. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  241. const end = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59);
  242. picker.$emit('pick', [start, end]);
  243. }
  244. }, {
  245. text: '当季',
  246. onClick(picker) {
  247. const date = new Date();
  248. const start = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3, 1, 0, 0, 0);
  249. const end = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3 + 3, 0, 23, 59, 59);
  250. picker.$emit('pick', [start, end]);
  251. }
  252. }, {
  253. text: '当年',
  254. onClick(picker) {
  255. const date = new Date();
  256. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  257. const end = new Date(date.getFullYear() + 1, 0, 0, 23, 59, 59);
  258. picker.$emit('pick', [start, end]);
  259. }
  260. }, {
  261. text: '最近一周',
  262. onClick(picker) {
  263. const date = new Date();
  264. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7, 0, 0, 0);
  265. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  266. picker.$emit('pick', [start, end]);
  267. }
  268. }, {
  269. text: '最近二周',
  270. onClick(picker) {
  271. const date = new Date();
  272. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 2, 0, 0, 0);
  273. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  274. picker.$emit('pick', [start, end]);
  275. }
  276. }, {
  277. text: '最近三周',
  278. onClick(picker) {
  279. const date = new Date();
  280. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 3, 0, 0, 0);
  281. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  282. picker.$emit('pick', [start, end]);
  283. }
  284. }]
  285. },
  286. treeOption: {
  287. addBtn: false,
  288. menu: false,
  289. size: "small",
  290. props: {
  291. labelText: "标题",
  292. label: "title",
  293. value: "value",
  294. }
  295. },
  296. treeData: [],
  297. form4: {},
  298. option4: {
  299. menuBtn: false,
  300. labelWidth: 80,
  301. column: [
  302. {
  303. label: "分类名称",
  304. prop: "cname",
  305. rules: [
  306. {
  307. required: true,
  308. message: "",
  309. trigger: "blur"
  310. }
  311. ],
  312. span: 24,
  313. },
  314. {
  315. label: "上级类型",
  316. prop: "parentId",
  317. dicData: [],
  318. type: "tree",
  319. props: {
  320. label: "cname",
  321. value: "id"
  322. },
  323. span: 24,
  324. }
  325. ]
  326. },
  327. hostUrl: '',
  328. option:{}
  329. };
  330. },
  331. components: {
  332. detailsPage,
  333. detailsInfo,
  334. corpType
  335. },
  336. async created() {
  337. this.option = await this.getColumnData(this.getColumnName(277.1), option);
  338. this.option.height = window.innerHeight - 330;
  339. this.getAllWorkDicts()
  340. this.findObject(this.option.column,'customerId').click = ()=>{
  341. this.$refs.crud.dicInit()
  342. }
  343. },
  344. activated() {
  345. this.$refs.crud.refreshTable();
  346. },
  347. methods: {
  348. derivation() {
  349. window.open(
  350. `/api/blade-client/partsCorps/export-template?${this.website.tokenHeader
  351. }=${getToken()}`
  352. );
  353. },
  354. //导出
  355. outExport() {
  356. let config = {params: {...this.search}}
  357. if (config.params) {
  358. for (const propName of Object.keys(config.params)) {
  359. const value = config.params[propName];
  360. if (value !== null && typeof (value) !== "undefined") {
  361. if (value instanceof Array) {
  362. for (const key of Object.keys(value)) {
  363. let params = propName + '[' + key + ']';
  364. config.params[params] = value[key]
  365. }
  366. delete config.params[propName]
  367. }
  368. }
  369. }
  370. }
  371. console.log(config.params);
  372. const routeData = this.$router.resolve({
  373. path: '/api/blade-sales-part/statisticsCorp/export', //跳转目标窗口的地址
  374. query: {
  375. ...config.params, //括号内是要传递给新窗口的参数
  376. corpType:'KH',
  377. identification:this.url
  378. }
  379. })
  380. window.open(routeData.href.slice(1, routeData.href.length) + '&' + `${this.website.tokenHeader}=${getToken()}`);
  381. },
  382. uploadBefore(file, done, loading) {
  383. done();
  384. loading = true;
  385. },
  386. uploadAfter(res, done, loading, column) {
  387. this.excelBox = false;
  388. let myError=res.toString();//转字符串
  389. myError=myError.replace("Error: ","") // 去掉前面的" Error: "
  390. this.$message.success(myError);
  391. this.refreshChange();
  392. loading = false;
  393. done();
  394. },
  395. filterNode(value, data) {
  396. console.log(value, data)
  397. if (!value) return true;
  398. return data.label.indexOf(value) !== -1;
  399. },
  400. nodeClick(data) {
  401. this.search.corpsTypeId = data.value
  402. this.page.currentPage = 1;
  403. this.onLoad(this.page, this.search);
  404. },
  405. getAllWorkDicts() {
  406. //状态
  407. // this.getWorkDicts("client_status").then(res => {
  408. // this.findObject(this.option.column, "status").dicData = res.data.data;
  409. // });
  410. getUser(JSON.parse(localStorage.getItem('saber-userInfo')).content.user_id).then(res=>{
  411. // this.form.salesCompanyName = res.data.data.deptName
  412. // this.form.salesCompanyId = res.data.data.deptId
  413. getCorpType({ corpType: 'KH'}).then(res => {
  414. this.treeData = res.data.data
  415. });
  416. })
  417. // customerList({ corpType: "KH" }).then(res => {
  418. // this.findObject(this.option4.column, "parentId").dicData = res.data.data.records
  419. // });
  420. this.$refs.crud.init();
  421. },
  422. searchCriteriaSwitch(type) {
  423. if (type) {
  424. this.option.height = this.option.height - 46;
  425. } else {
  426. this.option.height = this.option.height + 46;
  427. }
  428. this.$refs.crud.getTableHeight();
  429. },
  430. cellStyle() {
  431. return "padding:0;height:40px;";
  432. },
  433. //点击搜索按钮触发
  434. searchChange(params, done) {
  435. this.page.currentPage = 1;
  436. this.onLoad(this.page, params);
  437. done();
  438. },
  439. refreshChange() {
  440. this.onLoad(this.page, this.search);
  441. },
  442. newAdd() {
  443. this.show = false;
  444. },
  445. onLoad(page, params = {}) {
  446. let data = this.deepClone(Object.assign(params, this.search));
  447. if (data.date && data.date.length > 0) {
  448. data.startTime = data.date[0]
  449. data.endTime = data.date[1]
  450. }
  451. delete data.date
  452. data.corpType = "KH"
  453. this.loading = true;
  454. data.id = data.customerId
  455. delete data.customerId
  456. getList(
  457. page.currentPage,
  458. page.pageSize,
  459. data
  460. )
  461. .then(res => {
  462. this.dataList = res.data.data.records ? res.data.data.records : [];
  463. this.page.total = res.data.data.total;
  464. })
  465. .finally(() => {
  466. pageStatistics(data).then(res => {
  467. this.form = res.data.data
  468. })
  469. this.loading = false;
  470. });
  471. },
  472. addCorpType() {
  473. // this.$refs["corpType"].validate((valid, done) => {
  474. // done();
  475. // if (valid) {
  476. // addCorpType({ ...this.form4, corpType: 'KH', status: 0 })
  477. // .then(res => {
  478. // this.$message.success("保存成功");
  479. // this.getAllWorkDicts()
  480. // this.corpTypeVisible = false
  481. // })
  482. // } else {
  483. // return false;
  484. // }
  485. // });
  486. this.getAllWorkDicts()
  487. this.corpTypeVisible = false
  488. },
  489. corpTypeClosed() {
  490. // this.reload = Math.random();
  491. // this.form4 = this.$options.data().form4
  492. },
  493. viewInfo(row) {
  494. this.show = true;
  495. this.detailData = {
  496. id: row.id,
  497. };
  498. this.showInfo = false;
  499. },
  500. editOpen(row, status) {
  501. this.showInfo = true;
  502. this.detailData = {
  503. id: row.id,
  504. status: status
  505. };
  506. this.show = false;
  507. },
  508. currentChange(val) {
  509. this.page.currentPage = val;
  510. },
  511. sizeChange(val) {
  512. this.page.currentPage = 1;
  513. this.page.pageSize = val;
  514. },
  515. rowDel(row, index, done) {
  516. this.$confirm("确定删除数据?", {
  517. confirmButtonText: "确定",
  518. cancelButtonText: "取消",
  519. type: "warning"
  520. }).then(() => {
  521. remove({ id: row.id, corpType: "KH" }).then(res => {
  522. if (res.data.code == 200) {
  523. this.$message({
  524. type: "success",
  525. message: "删除成功!"
  526. });
  527. this.onLoad(this.page, this.search);
  528. }
  529. });
  530. });
  531. },
  532. async saveColumn() {
  533. const inSave = await this.saveColumnData(
  534. this.getColumnName(277.1),
  535. this.option
  536. );
  537. if (inSave) {
  538. this.$nextTick(() => {
  539. this.$refs.crud.doLayout();
  540. });
  541. this.$message.success("保存成功");
  542. //关闭窗口
  543. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  544. }
  545. },
  546. async resetColumn() {
  547. this.option = option;
  548. const inSave = await this.delColumnData(this.getColumnName(277.1), option);
  549. if (inSave) {
  550. this.$nextTick(() => {
  551. this.$refs.crud.doLayout();
  552. });
  553. this.getAllWorkDicts()
  554. this.$message.success("重置成功");
  555. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  556. }
  557. },
  558. //返回列表
  559. goBack() {
  560. this.detailData = this.$options.data().detailData;
  561. this.show = true;
  562. this.showInfo = true;
  563. this.$refs.crud.refreshTable();
  564. this.onLoad(this.page, this.search);
  565. },
  566. }
  567. }
  568. </script>
  569. <style lang="scss" scoped>
  570. .page-crad ::v-deep .basic-container__card {
  571. height: 94.2vh;
  572. }
  573. ::v-deep .el-form-item__error {
  574. display: none !important;
  575. }
  576. ::v-deep .el-input-group__append {
  577. padding: 0 0px !important;
  578. }
  579. .el-dialog ::v-deep .el-form-item__error {
  580. display: none !important;
  581. }
  582. .stat-td {
  583. text-align: center;
  584. position: relative;
  585. }
  586. .stat-img {
  587. width: 95%;
  588. height: 100px;
  589. }
  590. .stat-tip {
  591. position: absolute;
  592. left: 15px;
  593. top: 5px;
  594. .money {
  595. color: #fff;
  596. font-size: 28px;
  597. text-align: left;
  598. font-weight: 600;
  599. }
  600. .title {
  601. color: #fff;
  602. font-size: 14px;
  603. text-align: left;
  604. margin-top: 5px;
  605. margin-bottom: 0px;
  606. }
  607. }
  608. </style>