index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. <template>
  2. <div class="page-container">
  3. <div class="filter-container">
  4. <SelectJoin
  5. ref="selectJoinRef"
  6. :columns="selectJoinColumns"
  7. @change="onSelectJoinChange"
  8. />
  9. <div class="filter-item">
  10. <div class="filter-item-label">商品名称</div>
  11. <div class="filter-item-content">
  12. <el-input
  13. v-model="listQuery.productName"
  14. clearable
  15. placeholder="商品名称"
  16. @keyup.enter.native="handleFilter"
  17. class="filter-item-control"
  18. />
  19. </div>
  20. </div>
  21. <div class="filter-item">
  22. <div class="filter-item-label">客户经理</div>
  23. <div class="filter-item-content">
  24. <el-input
  25. v-model="listQuery.customerManagerName"
  26. clearable
  27. placeholder="客户经理"
  28. @keyup.enter.native="handleFilter"
  29. class="filter-item-control"
  30. />
  31. </div>
  32. </div>
  33. <div class="filter-item">
  34. <div class="filter-item-label">状态</div>
  35. <div class="filter-item-content">
  36. <el-select v-model="listQuery.status" clearable placeholder="状态">
  37. <el-option
  38. v-for="item in statusList"
  39. :key="item.value"
  40. :label="item.label"
  41. :value="item.value"
  42. />
  43. </el-select>
  44. </div>
  45. </div>
  46. <div class="filter-item">
  47. <el-button
  48. size="mini"
  49. type="warning"
  50. style="background: rgb(255, 148, 0);"
  51. @click="handleFilter"
  52. >
  53. 查询
  54. </el-button>
  55. <el-button size="mini" type="primary" plain @click="handleFilterReset"
  56. >重置
  57. </el-button>
  58. </div>
  59. </div>
  60. <div class="head-line" />
  61. <div class="action-container">
  62. <el-button
  63. icon="el-icon-plus"
  64. size="mini"
  65. type="primary"
  66. @click="handleCreate"
  67. >
  68. 新增
  69. </el-button>
  70. <!-- <el-button icon="el-icon-plus" size="mini" type="primary" @click="onRewardDialogOpen">
  71. 拓新激励
  72. </el-button> -->
  73. <el-button
  74. icon="el-icon-document"
  75. size="mini"
  76. type="primary"
  77. plain
  78. @click="importExcel"
  79. >
  80. 导入
  81. </el-button>
  82. <el-button
  83. icon="el-icon-download"
  84. type="primary"
  85. plain
  86. @click="downloadTemplate"
  87. >
  88. 下载模版
  89. </el-button>
  90. <el-button icon="el-icon-download" type="primary" @click="exportExcel">
  91. 导出到excel
  92. </el-button>
  93. <el-button icon="el-icon-download" type="primary" @click="exportExcel2">
  94. 导出房间企业信息
  95. </el-button>
  96. </div>
  97. <el-table v-loading="listLoading" :data="list" border style="width: 100%;">
  98. <el-table-column type="index" align="center" label="序号" width="50" />
  99. <el-table-column prop="roomInfo" align="center" label="房间号" />
  100. <el-table-column prop="virtName" align="center" label="企业名称" />
  101. <el-table-column prop="residentNum" align="center" label="常驻人数" />
  102. <el-table-column
  103. prop="merchantQuantityInfo"
  104. align="center"
  105. label="商品名称"
  106. />
  107. <el-table-column prop="status" align="center" label="状态">
  108. <template slot-scope="{ row }">
  109. {{ row.status | enumFormatter(statusList) }}
  110. </template>
  111. </el-table-column>
  112. <el-table-column
  113. prop="customerManagerName"
  114. align="center"
  115. label="客户经理"
  116. />
  117. <el-table-column
  118. fixed="right"
  119. header-align="center"
  120. align="center"
  121. width="200"
  122. label="操作"
  123. >
  124. <template slot-scope="{ row, $index }">
  125. <div class="operate-container">
  126. <span class="operate-btn" @click="handleUpdate(row, $index)">
  127. 修改
  128. </span>
  129. <span
  130. class="operate-btn"
  131. @click="onJiaoshuimaDialogOpen(row, $index)"
  132. >
  133. 叫水码
  134. </span>
  135. <!-- <span class="operate-btn" @click="handleDelete(row, $index)">
  136. 删除
  137. </span> -->
  138. </div>
  139. </template>
  140. </el-table-column>
  141. </el-table>
  142. <pagination
  143. v-show="total > 0"
  144. :total="total"
  145. :page.sync="listQuery.page"
  146. :limit.sync="listQuery.limit"
  147. @pagination="getList"
  148. />
  149. <!-- 拓新激励 -->
  150. <el-dialog
  151. width="400px"
  152. title="拓新激励"
  153. :visible="rewardDialogVisible"
  154. :before-close="onRewardDialogClose"
  155. >
  156. <el-form ref="postForm" :model="rewardPostForm" label-width="100px">
  157. <el-form-item label="开拓奖励" prop="textarea">
  158. <div>
  159. <number-input
  160. v-model="rewardPostForm.price"
  161. :value="rewardPostForm.price"
  162. placeholder="请输入金额"
  163. />
  164. <span>元/企业</span>
  165. </div>
  166. </el-form-item>
  167. </el-form>
  168. <div slot="footer" class="dialog-footer">
  169. <el-button
  170. type="primary"
  171. @click="onRewardSubmit"
  172. :loading="rewardSubmitLoading"
  173. >确定</el-button
  174. >
  175. </div>
  176. </el-dialog>
  177. <!-- 叫水码 -->
  178. <el-dialog
  179. width="400px"
  180. title="叫水码"
  181. :visible="jiaoshuimaDialogVisible"
  182. :before-close="onJiaoshuimaDialogClose"
  183. >
  184. <div style="margin: 0 auto 20px;text-align:center;">
  185. {{ jiaoshuimaPostForm.virtName }}
  186. </div>
  187. <div
  188. id="qrcode"
  189. style="width:250px;height:250px;overflow: hidden;margin: 0 auto;"
  190. ref="qrcode"
  191. ></div>
  192. <div class="a">
  193. {{ jiaoshuimaPostForm.link }}
  194. </div>
  195. <div slot="footer" class="dialog-footer">
  196. <el-button
  197. type="primary"
  198. v-clipboard:copy="jiaoshuimaPostForm.link"
  199. v-clipboard:success="onJiaoshuimaDialogCopy"
  200. >复制链接</el-button
  201. >
  202. <el-button type="primary" @click="onJiaoshuimaDialogDownload"
  203. >下载二维码</el-button
  204. >
  205. </div>
  206. </el-dialog>
  207. <import-excel
  208. ref="importExcel"
  209. :visible.sync="importExcelVisible"
  210. @submit="onImportExcelSubmit"
  211. ></import-excel>
  212. </div>
  213. </template>
  214. <script>
  215. import API_FLASHDELIVER_JIAOSHUIMA from "@/api/flashdeliver/jiaoshuima";
  216. import {
  217. companyGetselectlist,
  218. organizationGetselectlist,
  219. organisationVirtualarchitectureList
  220. } from "@/api/flashdeliver/jiaoshuima";
  221. import Pagination from "@/components/Pagination";
  222. var pageFlag = false;
  223. // 状态列表
  224. export const statusList = [
  225. { label: "待转化", value: 2 },
  226. { label: "未启用", value: 1 },
  227. { label: "客户", value: 3 }
  228. ];
  229. import NumberInput from "@/components/NumberInput";
  230. import ImportExcel from "./components/ImportExcel";
  231. import FileSaver from "file-saver";
  232. import QRCode from "qrcodejs2";
  233. import SelectJoin from "./components/SelectJoin";
  234. export default {
  235. name: "jiaoshuima",
  236. components: {
  237. Pagination,
  238. NumberInput,
  239. SelectJoin,
  240. ImportExcel
  241. },
  242. data() {
  243. return {
  244. selectJoinColumns: this.getSelectJoinColumn(),
  245. tableKey: 0,
  246. list: [],
  247. total: 0,
  248. listLoading: false,
  249. listQuery: {
  250. page: 1,
  251. limit: 10,
  252. productName: "",
  253. status: null,
  254. customerManagerName: "",
  255. virtId: "",
  256. virtName: "",
  257. projectId: "",
  258. operationsCenterId: ""
  259. },
  260. statusList,
  261. operationsCenterList: [], // 运营中心列表
  262. projectList: [], // 项目列表
  263. virtList: [], // 企业列表
  264. loading: false,
  265. // 导入excel
  266. importExcelVisible: false,
  267. importExcelLoading: false,
  268. // 拓新激励弹窗
  269. rewardDialogVisible: false,
  270. rewardSubmitLoading: false,
  271. rewardPostForm: {
  272. price: null
  273. },
  274. // 叫水码弹窗
  275. jiaoshuimaDialogVisible: false,
  276. jiaoshuimaPostForm: {
  277. virtName: "",
  278. link: ""
  279. // link: "http://wx.palmnest.com/super_cloud/api/wechat/q/r?p=3&p1=615&p2=185&p3=&_s=0"
  280. }
  281. };
  282. },
  283. computed: {
  284. userInfo() {
  285. return this.$store.getters.userInfo;
  286. }
  287. },
  288. created() {
  289. console.log("created");
  290. pageFlag = true;
  291. this.getPage();
  292. },
  293. activated() {
  294. console.log("activated");
  295. if (pageFlag) {
  296. pageFlag = false;
  297. return;
  298. }
  299. this.getPage();
  300. },
  301. methods: {
  302. getSelectJoinColumn() {
  303. return [
  304. {
  305. field: "operationsCenterId",
  306. value: "",
  307. defaultValue: "",
  308. label: "运营中心",
  309. fileNames: { label: "label", value: "value", options: "items" },
  310. componentProps: {
  311. clearable: true,
  312. filterable: true,
  313. placeholder: "请选择运营中心"
  314. },
  315. options: [],
  316. api: () => {
  317. return companyGetselectlist();
  318. },
  319. afterFetch: data => {
  320. if (data && data.length) {
  321. const operationsCenterId = data[0].value;
  322. this.listQuery.operationsCenterId = operationsCenterId;
  323. this.$refs.selectJoinRef.setColumnValue(0, operationsCenterId)
  324. }
  325. return data;
  326. }
  327. },
  328. {
  329. field: "projectId",
  330. value: "",
  331. defaultValue: "",
  332. label: "项目",
  333. componentProps: {
  334. clearable: true,
  335. filterable: true,
  336. placeholder: "请选择项目"
  337. },
  338. options: [],
  339. api: () => {
  340. const params = {
  341. pageNo: 1,
  342. pageSize: 999
  343. };
  344. this.listQuery.operationsCenterId &&
  345. (params[
  346. "conditions[companyId]"
  347. ] = this.listQuery.operationsCenterId);
  348. return organizationGetselectlist(params);
  349. }
  350. },
  351. {
  352. field: "virtId",
  353. value: "",
  354. defaultValue: "",
  355. label: "企业",
  356. options: [],
  357. api: async () => {
  358. const params = {
  359. pageNo: 1,
  360. pageSize: 999
  361. };
  362. this.listQuery.projectId &&
  363. (params["conditions[orgId]"] = this.listQuery.projectId);
  364. return await organisationVirtualarchitectureList(params);
  365. }
  366. }
  367. ];
  368. },
  369. onSelectJoinChange({ selectedValues }) {
  370. console.log(`onSelectJoinChange`, selectedValues);
  371. this.selectJoinColumns.forEach(column => {
  372. this.listQuery[column.field] = column.value;
  373. });
  374. // if (res.data && res.data.length) {
  375. // const operationsCenterId = res.data[0].value;
  376. // this.listQuery.operationsCenterId = operationsCenterId;
  377. // this.getProjectList();
  378. // }
  379. },
  380. enumFormatter(
  381. val,
  382. arr,
  383. key = "value",
  384. label = "label",
  385. def = EMPTY_PLACEHOLDER
  386. ) {
  387. const target = arr.find(v => v[key] === val);
  388. if (label === "obj") {
  389. return target;
  390. } else {
  391. return target ? target[label] : def;
  392. }
  393. },
  394. async getPage() {
  395. // if (this.userInfo.userTypeModel == "project") {
  396. // this.listQuery.operationsCenterId = this.userInfo.companyId;
  397. // this.listQuery.projectId = this.userInfo.orgId;
  398. // this.getVirtList();
  399. // } else if (this.userInfo.userTypeModel == "operationsCenter") {
  400. // this.listQuery.operationsCenterId = this.userInfo.companyId;
  401. // await this.getProjectList();
  402. // } else {
  403. // await this.getOperationsCenterList();
  404. // }
  405. this.$nextTick(async () => {
  406. await this.$refs.selectJoinRef.loadData();
  407. this.getList();
  408. });
  409. },
  410. getListQueryModel() {
  411. const params = {
  412. pageNo: this.listQuery.page,
  413. pageSize: this.listQuery.limit,
  414. conditions: {}
  415. };
  416. this.listQuery.operationsCenterId &&
  417. (params.conditions.operationsCenterId = this.listQuery.operationsCenterId);
  418. this.listQuery.projectId &&
  419. (params.conditions.orgId = this.listQuery.projectId);
  420. this.listQuery.virtId &&
  421. (params.conditions.virtId = this.listQuery.virtId);
  422. this.listQuery.virtId &&
  423. (params.conditions.virtName = this.listQuery.virtName);
  424. this.listQuery.productName &&
  425. (params.conditions.productName = this.listQuery.productName);
  426. this.listQuery.customerManagerName &&
  427. (params.conditions.customerManagerName = this.listQuery.customerManagerName);
  428. this.statusList.some(v => v.value === this.listQuery.status) &&
  429. (params.conditions.status = this.listQuery.status);
  430. return params;
  431. },
  432. getList() {
  433. this.listLoading = true;
  434. API_FLASHDELIVER_JIAOSHUIMA.page(this.getListQueryModel())
  435. .then(res => {
  436. this.list = res.data;
  437. this.total = res.count;
  438. })
  439. .finally(() => {
  440. this.listLoading = false;
  441. });
  442. },
  443. // 查询
  444. handleFilter() {
  445. this.getList();
  446. },
  447. // 重置
  448. handleFilterReset() {
  449. this.listQuery.virtId = "";
  450. this.listQuery.virtName = "";
  451. this.listQuery.customerManagerName = "";
  452. this.listQuery.productName = "";
  453. this.listQuery.status = null;
  454. },
  455. handleCreate() {
  456. const query = {};
  457. this.handleAddOrUpdate(query);
  458. },
  459. handleUpdate(row, index) {
  460. const { id, virtId, roomMarkId } = row;
  461. const query = { id, virtId, roomMarkId };
  462. this.handleAddOrUpdate(query);
  463. },
  464. handleAddOrUpdate(query) {
  465. this.$router.push({
  466. path: "/flashdeliver/jiaoshuima/add-or-update",
  467. query
  468. });
  469. },
  470. handleDelete(row, index) {
  471. this.$confirm("确认删除" + row.name + "?", "提示", {
  472. confirmButtonText: "确定",
  473. cancelButtonText: "取消",
  474. type: "warning"
  475. })
  476. .then(() => {
  477. API_FLASHDELIVER_JIAOSHUIMA.del(row.id).then(res => {
  478. this.$message({
  479. type: "success",
  480. message: "删除成功!",
  481. duration: 1500
  482. });
  483. this.list.splice(index, 1);
  484. this.total -= 1;
  485. });
  486. })
  487. .catch(() => {});
  488. },
  489. onRewardDialogOpen() {
  490. this.rewardDialogVisible = true;
  491. },
  492. onRewardDialogClose() {
  493. this.rewardDialogVisible = false;
  494. },
  495. onJiaoshuimaDialogOpen(row, _index) {
  496. this.jiaoshuimaPostForm = {
  497. virtId: row.virtId,
  498. virtName: row.virtName,
  499. link: row.waterCodeUrl
  500. };
  501. if (row.waterCodeUrl) {
  502. this.jiaoshuimaDialogVisible = true;
  503. this.$nextTick(() => {
  504. this.$refs.qrcode.innerHTML = ""; // 避免重复生成Dom
  505. let qrCode = new QRCode(this.$refs.qrcode, {
  506. width: 500,
  507. height: 500,
  508. text: this.jiaoshuimaPostForm.link
  509. });
  510. });
  511. } else {
  512. this.$message.error("叫水码地址为空!");
  513. }
  514. },
  515. onJiaoshuimaDialogClose() {
  516. this.jiaoshuimaDialogVisible = false;
  517. },
  518. onJiaoshuimaDialogCopy() {
  519. this.$message({
  520. type: "success",
  521. message: "成功复制",
  522. duration: 2000
  523. });
  524. },
  525. onJiaoshuimaDialogDownload() {
  526. // const base64 = this.$refs.qrcode.children[1].src;
  527. const canvas = this.$refs.qrcode.children[0];
  528. canvas.toBlob(blob => {
  529. FileSaver.saveAs(blob, "waterCodeUrl.png");
  530. });
  531. },
  532. onRewardSubmit() {
  533. this.rewardSubmitLoading = true;
  534. },
  535. onImportExcelSubmit() {
  536. this.importExcelVisible = false;
  537. this.getList();
  538. },
  539. // 导入
  540. importExcel() {
  541. if (this.userInfo.userTypeModel == "operationsCenter") {
  542. this.$refs.importExcel.postForm.operationsCenterId = this.userInfo.companyId;
  543. this.$refs.importExcel.init();
  544. } else if (this.userInfo.userTypeModel == "project") {
  545. this.$refs.importExcel.postForm.operationsCenterId = this.userInfo.companyId;
  546. this.$refs.importExcel.postForm.projectId = this.userInfo.orgId;
  547. } else {
  548. this.$refs.importExcel.init();
  549. }
  550. this.importExcelVisible = true;
  551. this.$refs.importExcel.userInfo = this.userInfo;
  552. },
  553. // 导出
  554. exportExcel() {
  555. if (!this.list.length) {
  556. this.$message.error("还没有数据!");
  557. return;
  558. }
  559. this.$confirm("此操作将导出报表数据, 是否继续?", "提示", {
  560. confirmButtonText: "确定",
  561. cancelButtonText: "取消",
  562. type: "warning"
  563. })
  564. .then(() => {
  565. API_FLASHDELIVER_JIAOSHUIMA.exportExcel(
  566. this.getListQueryModel()
  567. ).then(res => {
  568. const rootUrl = process.env.BASE_API.substring(
  569. 0,
  570. process.env.BASE_API.length - 3
  571. );
  572. const linkUrl = rootUrl + "template/WaterCode.xls";
  573. console.log("导出叫水码excel地址", linkUrl);
  574. location.href = linkUrl;
  575. });
  576. })
  577. .catch(() => {});
  578. },
  579. exportExcel2() {
  580. if (!this.list.length) {
  581. this.$message.error("还没有数据!");
  582. return;
  583. }
  584. if (!this.listQuery.projectId) {
  585. this.$message.error("请选择项目!");
  586. return;
  587. }
  588. this.$confirm("此操作将导出报表数据, 是否继续?", "提示", {
  589. confirmButtonText: "确定",
  590. cancelButtonText: "取消",
  591. type: "warning"
  592. })
  593. .then(() => {
  594. API_FLASHDELIVER_JIAOSHUIMA.exportRoomInfo(
  595. this.getListQueryModel()
  596. ).then(res => {
  597. const rootUrl = process.env.BASE_API.substring(
  598. 0,
  599. process.env.BASE_API.length - 3
  600. );
  601. const link = rootUrl + "template/RoomVirtName.xls";
  602. console.log("导出项目下房间和企业信息excel地址", link);
  603. location.href = link;
  604. });
  605. })
  606. .catch(() => {});
  607. },
  608. downloadTemplate() {
  609. let rootUrl = process.env.BASE_API.substring(
  610. 0,
  611. process.env.BASE_API.length - 3
  612. );
  613. const link = rootUrl + "template/WaterCodeTemplate.xls";
  614. console.log("下载叫水码模版", link);
  615. location.href = link;
  616. },
  617. onOperationsCenterChange() {
  618. this.listQuery.projectId = "";
  619. this.handleFilterReset();
  620. this.getProjectList();
  621. },
  622. onProjectChange() {
  623. this.handleFilterReset();
  624. this.getVirtList();
  625. },
  626. onVirtChange() {
  627. this.listQuery.virtName = this.virtList.find(
  628. v => v.value === this.listQuery.virtId
  629. ).label;
  630. },
  631. async getVirtList() {
  632. const params = {
  633. pageNo: 1,
  634. pageSize: 999
  635. };
  636. this.listQuery.projectId &&
  637. (params["conditions[orgId]"] = this.listQuery.projectId);
  638. const res = await organisationVirtualarchitectureList(params);
  639. this.virtList = res.data || [];
  640. if (res.data && res.data.length === 1) {
  641. this.listQuery.virtId = res.data[0].value;
  642. this.listQuery.virtName = res.data[0].label;
  643. }
  644. },
  645. async getProjectList() {
  646. const params = {
  647. pageNo: 1,
  648. pageSize: 999
  649. };
  650. this.listQuery.operationsCenterId &&
  651. (params["conditions[companyId]"] = this.listQuery.operationsCenterId);
  652. const res = await organizationGetselectlist(params);
  653. this.projectList = res.data;
  654. if (res.data && res.data.length === 1) {
  655. this.listQuery.projectId = res.data[0].value;
  656. this.getVirtList();
  657. }
  658. },
  659. async getOperationsCenterList() {
  660. const res = await companyGetselectlist();
  661. this.operationsCenterList = res.data;
  662. if (res.data && res.data.length) {
  663. const operationsCenterId = res.data[0].value;
  664. this.listQuery.operationsCenterId = operationsCenterId;
  665. this.getProjectList();
  666. }
  667. }
  668. }
  669. };
  670. </script>
  671. <style lang="scss" scoped>
  672. .filter-container {
  673. display: flex;
  674. flex-wrap: wrap;
  675. padding-bottom: 0;
  676. .filter-item {
  677. display: flex;
  678. align-items: center;
  679. margin-right: 10px;
  680. margin-bottom: 18px;
  681. &-label {
  682. box-sizing: border-box;
  683. font-size: 14px;
  684. color: #606266;
  685. font-weight: bold;
  686. padding: 0 12px 0 0;
  687. }
  688. }
  689. }
  690. .action-container {
  691. margin-bottom: 20px;
  692. }
  693. .operate-container {
  694. text-align: center;
  695. }
  696. .operate-btn {
  697. margin: 0 4px;
  698. cursor: pointer;
  699. color: #409eff;
  700. }
  701. </style>