index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. <template>
  2. <!-- 主页 -->
  3. <div class="homePage flex-col">
  4. <div class="homeBox">
  5. <s-header :name="sys ? sys.title : $t('public.sysName')" :noback="true" :isFixed="false"></s-header>
  6. <!-- 留言滚动条 -->
  7. <template v-if="noticeContent.title">
  8. <van-notice-bar @click="noticeClk" mode="link" :scrollable="true" color="rgba(64,77,116,1)" background="#fff"
  9. left-icon="volume-o" :text="noticeContent.title" />
  10. </template>
  11. <div class="intervalRow"></div>
  12. <div class="nameDeviceRow flex-col">
  13. <span class="txt3">{{ userName }}</span>
  14. <div class="l-flex-RC">
  15. <span class="info3" style="color: #4d6add;">{{ $t("home.totalEquipment") }} : {{ equipStatus.machineTotalNum }}</span>
  16. <div class="lineCon o-mlr-6"></div>
  17. <span class="word2" style="color: #07c160;">{{ $t("home.running") }} : {{ equipStatus.machineUseNum }}</span>
  18. </div>
  19. </div>
  20. <!-- 没有数据概览M14权限的人看不到数据概览和ECharts -->
  21. <!-- 数据概览 -->
  22. <div v-if="showDataDiv" class="titleBox flex-col">
  23. <div class="layer2 flex-row">
  24. <div class="section5 flex-col"></div>
  25. <div class="TextGroup2 flex-col">
  26. <span class="txt4">{{ $t("home.dataOverview") }}</span>
  27. </div>
  28. </div>
  29. </div>
  30. <!-- 时间选择 -->
  31. <dateSelectList v-if="showDataDiv" @update="update($event)"></dateSelectList>
  32. <typeSelectList v-if="showDataDiv" :isHome="true" @upselectdata="upselectdata($event)"></typeSelectList>
  33. <!-- 订单数据 -->
  34. <div v-if="showDataDiv" class="o-plr-8 o-pt-10">
  35. <div class="outer5 flex-col" @click="pushOrderCenter">
  36. <div class="block5 flex-col">
  37. <div class="topTitle flex-row justify-end">
  38. <span class="txt10">{{ $t("home.orderData") }}</span>
  39. <div class="layer4 flex-col"></div>
  40. </div>
  41. <div class="outerBox flex-row">
  42. <div class="main4 flex-col justify-between">
  43. <div class="main5 flex-row justify-center">
  44. <!-- 首页 - 订单数据 - 收入总额¥ -->
  45. <!-- <span class="word8">&yen;</span> -->
  46. <span class="word8">{{ currencySymbol }}</span>
  47. <span class="word9">{{ salesVolume.toFixed(0) }}</span>
  48. </div>
  49. <span class="info5">{{ $t("home.totalIncome") }}</span>
  50. </div>
  51. <div class="TextGroup7 flex-col">
  52. <div class="mod3 flex-col justify-between">
  53. <span class="txt8">{{ salesNumber }}</span>
  54. <span class="info6">{{ $t("home.productNum") }}</span>
  55. </div>
  56. </div>
  57. <div class="TextGroup8 flex-col">
  58. <div class="outer6 flex-col justify-between">
  59. <span class="txt9">{{ orderNumber }}</span>
  60. <span class="word10">{{ $t("home.numberOfOrders") }}</span>
  61. </div>
  62. </div>
  63. </div>
  64. </div>
  65. </div>
  66. </div>
  67. <!-- 时间 -->
  68. <div v-if="showDataDiv" class="c-text-c c-text-18">
  69. {{ Format_time(dateSelect.startDate, 'YYYY-MM-DD') }}--{{ Format_time(dateSelect.endDate, 'YYYY-MM-DD') }}
  70. </div>
  71. <!-- ECharts
  72. <template v-if="showDataDiv && !noData(salesVolume, salesNumber)">
  73. <div ref="chartBox" class="Chart1 flex-col"></div>
  74. </template>
  75. <template v-else>
  76. <kNoData v-if="showDataDiv"></kNoData>
  77. </template> -->
  78. <!-- <div> -->
  79. <div v-if="showDataDiv && !noData(salesVolume, salesNumber)">
  80. <div ref="chartBox" class="Chart1 flex-col"></div>
  81. </div>
  82. <kNoData v-else></kNoData>
  83. <!-- </div> -->
  84. <!-- 常用工具 -->
  85. <div class="outer9 flex-col justify-center">
  86. <div class="main24 flex-col justify-between">
  87. <div class="ImageText10 flex-col">
  88. <div class="wrap2 flex-row justify-between">
  89. <div class="outer10 flex-col"></div>
  90. <div class="TextGroup13 flex-col">
  91. <span class="txt13">{{ $t("home.commonTools") }}</span>
  92. </div>
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. <div class="outer11 flex-row">
  98. <div class="main25 flex-col" v-for="(item, index) in pushToolList" :key="index" @click="pushToolPage(item.value)">
  99. <img class="mod7 flex-col" :src="showLogo(item.value)" />
  100. <div class="TextGroup14 flex-col">
  101. <!-- <span class="info15" v-html="item.label"></span> -->
  102. <span class="info15">{{ $t(item.label) }}</span>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. <!-- 通知弹窗 -->
  108. <kDialog :dialogTitle="$t('home.notificationPop.notification')" :cancelBtnTxt="$t('home.notificationPop.nextTime')"
  109. :confirmBtnTxt="$t('home.notificationPop.roger')" ref="kDialogRef" @confirmclk="confirmClk">
  110. <template #content>
  111. <div class="o-w" style="max-height: 50vh; overflow-y: auto" v-html="noticeContent.note"></div>
  112. </template>
  113. </kDialog>
  114. <!-- <nav-bar></nav-bar> -->
  115. </div>
  116. </template>
  117. <script>
  118. // 导入无数据组件
  119. import kNoData from "../../components/commom/kNoData/index.vue";
  120. import kDialog from "../../components/commom/kDialog/index.vue";
  121. import { onMounted, ref, nextTick } from "vue";
  122. import sHeader from "../../components/SimpleHeader";
  123. // import navBar from "../../components/NavBar";
  124. import dateSelectList from "../../components/dateSelectList";
  125. import typeSelectList from "../../components/typeSelectList";
  126. import { getLoginUser, $M_Menus, Format_time, styleUrl } from "../../common/js/utils";
  127. import { useRouter } from "vue-router";
  128. import {
  129. getStatistics,
  130. Api_getNotice,
  131. Api_postMachineNum,
  132. Api_getUpdateNotice,
  133. } from "../../service/home";
  134. import dateUtil from "../../utils/dateUtil";
  135. import { useI18n } from "vue-i18n";
  136. import { showToast } from "vant";
  137. export default {
  138. name: "home",
  139. components: {
  140. sHeader,
  141. // navBar,
  142. dateSelectList,
  143. typeSelectList,
  144. kDialog,
  145. kNoData,
  146. },
  147. setup() {
  148. // 设备状况
  149. const equipStatus = ref({});
  150. // 获取设备情况
  151. const getMachineNum = () => {
  152. Api_postMachineNum({ adminId: user.id }).then((res) => {
  153. // console.log("res", res);
  154. equipStatus.value = res.data.data || {};
  155. });
  156. };
  157. const noticeContent = ref({});
  158. // 获取公告
  159. const getNotice = () => {
  160. Api_getNotice({ adminId: user.id }).then((res) => {
  161. // console.log("res", res);
  162. noticeContent.value = res.data.data || {};
  163. });
  164. };
  165. const { t } = useI18n();
  166. // 通知弹窗
  167. const kDialogRef = ref(null);
  168. // 点击通知栏
  169. const noticeClk = () => {
  170. kDialogRef.value.openDialog();
  171. };
  172. // 点击右侧按钮
  173. const confirmClk = (e) => {
  174. console.log(e, 2222);
  175. Api_getUpdateNotice({
  176. adminId: user.id,
  177. }).then((res) => {
  178. // console.log("res", res);
  179. showToast(res.data.message);
  180. setTimeout(() => {
  181. getNotice();
  182. }, 500);
  183. });
  184. };
  185. const user = getLoginUser();
  186. const router = useRouter();
  187. const userName = ref(user.name);
  188. const sys = ref(null);
  189. // 自定义货币符号
  190. const currencySymbol = ref("¥");
  191. if (user.currencySymbol) {
  192. currencySymbol.value = user.currencySymbol;
  193. } else {
  194. currencySymbol.value = "¥";
  195. }
  196. // console.log("currencySymbol是》》》" + user.currencySymbol);
  197. // 图表对象
  198. const chartBox = ref();
  199. let chartObj = null;
  200. // 跳转订单中心
  201. const pushOrderCenter = () => {
  202. router.push({ path: "/orderCenter" });
  203. };
  204. const dateSelect = ref({});
  205. const update = (uDate) => {
  206. dateSelect.value = uDate;
  207. getStatisticsFun();
  208. };
  209. let typeSelectData = {};
  210. const upselectdata = (uSData) => {
  211. typeSelectData = uSData;
  212. getStatisticsFun();
  213. };
  214. const salesVolume = ref(0);
  215. const salesNumber = ref(0);
  216. const orderNumber = ref(0);
  217. // 查询图表
  218. const getStatisticsFun = async () => {
  219. const params = {
  220. ...dateSelect.value,
  221. // ...typeSelectData,
  222. adminId: user.id,
  223. ifForeign: typeSelectData.ifForeign === '' ? user.ifForeign : typeSelectData.ifForeign,
  224. payType: typeSelectData.payType,
  225. clientId: typeSelectData.clientId,
  226. username: typeSelectData.userName, // 商家
  227. companyType: typeSelectData.companyType, // 公司平台
  228. machineType: typeSelectData.machineType, // 设备类型
  229. equipmentId:
  230. typeSelectData.equipmentId === "" ? null : typeSelectData.equipmentId,
  231. };
  232. const { data } = await getStatistics(params);
  233. if (data.code && data.data) {
  234. salesVolume.value = 0;
  235. salesNumber.value = 0;
  236. orderNumber.value = 0;
  237. data.data.series[0].data.forEach((item) => {
  238. salesNumber.value = parseInt(salesNumber.value + item);
  239. });
  240. data.data.series[1].data.forEach((item) => {
  241. salesVolume.value = parseFloat(salesVolume.value) + parseFloat(item);
  242. });
  243. data.data.series[2].data.forEach((item) => {
  244. orderNumber.value = parseInt(orderNumber.value + item);
  245. });
  246. data.data.categories.forEach((item, index) => {
  247. if (item == "周1") {
  248. data.data.categories[index] = t("home.week.mon");
  249. }
  250. if (item == "周2") {
  251. data.data.categories[index] = t("home.week.tue");
  252. }
  253. if (item == "周3") {
  254. data.data.categories[index] = t("home.week.wed");
  255. }
  256. if (item == "周4") {
  257. data.data.categories[index] = t("home.week.thu");
  258. }
  259. if (item == "周5") {
  260. data.data.categories[index] = t("home.week.fri");
  261. }
  262. if (item == "周6") {
  263. data.data.categories[index] = t("home.week.sat");
  264. }
  265. if (item == "周日") {
  266. data.data.categories[index] = t("home.week.sun");
  267. }
  268. })
  269. // 解决eacharts与v-if的渲染问题
  270. await nextTick();
  271. if (chartBox.value) {
  272. chartObj = window.echarts.init(chartBox.value, null, {
  273. renderer: "canvas",
  274. useDirtyRect: false,
  275. });
  276. const option = {
  277. tooltip: {
  278. trigger: "axis",
  279. axisPointer: {
  280. type: "shadow",
  281. },
  282. },
  283. grid: {
  284. left: "3%",
  285. right: "4%",
  286. bottom: "10%",
  287. containLabel: true,
  288. },
  289. legend: {
  290. bottom: 0,
  291. right: 10,
  292. itemWidth: 10,
  293. itemHeight: 10,
  294. icon: "rect",
  295. },
  296. // 固定屏幕显示多少个,其余的滑动
  297. dataZoom: [
  298. // {
  299. // type: 'slider',
  300. // xAxisIndex: 0,
  301. // filterMode: 'none',
  302. // // 开始的值
  303. // startValue: null,
  304. // // 结束的值
  305. // endValue: null,
  306. // // 锁定滑动的区域
  307. // // zoomLock:true,
  308. // },
  309. {
  310. type: "inside",
  311. xAxisIndex: 0,
  312. filterMode: "none",
  313. startValue: null,
  314. endValue: null,
  315. zoomLock: true,
  316. },
  317. ],
  318. xAxis: {
  319. type: "category",
  320. axisLabel: {
  321. rotate: 45,
  322. },
  323. data: data.data.categories,
  324. },
  325. yAxis: {
  326. type: "value",
  327. },
  328. series: [
  329. {
  330. ...data.data.series[0],
  331. type: "bar",
  332. itemStyle: { color: "#e59a6d" },
  333. name: t("home.productNum"),
  334. label: {
  335. show: true,
  336. position: "top",
  337. },
  338. },
  339. {
  340. ...data.data.series[1],
  341. type: "bar",
  342. itemStyle: { color: "#4d6add" },
  343. name: t("home.salesAmount"),
  344. label: {
  345. show: true,
  346. position: "top",
  347. },
  348. },
  349. ],
  350. };
  351. option.dataZoom[0]["startValue"] =
  352. data.data.categories[data.data.categories.length - 5];
  353. option.dataZoom[0]["endValue"] =
  354. data.data.categories[data.data.categories.length - 1];
  355. chartObj && chartObj.setOption(option);
  356. //图形宽度随屏幕宽度改变而改变
  357. window.onresize = chartObj.resize;
  358. }
  359. }
  360. };
  361. const pushToolList = ref([]);
  362. // 页面初始化
  363. onMounted(() => {
  364. // 加载样式
  365. styleUrl('home');
  366. if (localStorage.getItem("loginSys")) {
  367. const loginSysString = localStorage.getItem("loginSys");
  368. sys.value = JSON.parse(loginSysString);
  369. }
  370. // 设置菜单权限
  371. menuSet();
  372. // 设置菜单权限, 只执行一次
  373. // once(menuSet);
  374. dateSelect.value = {
  375. chartType: "day",
  376. startDate: dateUtil.formateDate(
  377. new Date(new Date(new Date().getTime()).setHours(0, 0, 0, 0)),
  378. "yyyy-MM-dd hh:mm:ss"
  379. ),
  380. endDate: dateUtil.formateDate(
  381. new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 59)),
  382. "yyyy-MM-dd hh:mm:ss"
  383. ),
  384. };
  385. typeSelectData = {
  386. userName: user.username,
  387. clientId: null,
  388. };
  389. getStatisticsFun();
  390. // 获取首页公告
  391. getNotice();
  392. // 获取设备情况
  393. getMachineNum();
  394. });
  395. const menuList = [];
  396. const showDataDiv = ref(false);
  397. const isOrderData = ref(false);
  398. // 设置菜单权限
  399. const menuSet = () => {
  400. // 清空菜单列表
  401. menuList.length = 0;
  402. // 组合菜单权限
  403. user.menuCodeList.forEach((item) => {
  404. for (const key in $M_Menus) {
  405. // 设备管理M1,设备查看M2,订单数据M4,任务消息M6,数据概览M14,订单退款M16,系统脱机M17 这些图标不用加载到底部菜单上
  406. if (
  407. item === key &&
  408. (
  409. item !== "M1" &&
  410. item !== "M2" && // M2本身就无logo
  411. item !== "M4" &&
  412. item !== "M6" &&
  413. item !== "M14" &&
  414. item !== "M16" &&
  415. item !== "M17"
  416. )
  417. ) {
  418. menuList.push({
  419. label: $M_Menus[key],
  420. value: item
  421. });
  422. }
  423. }
  424. });
  425. // 赋值菜单
  426. pushToolList.value = menuList;
  427. // 查询是否有apk管理权限
  428. const isApkMan = user.menuCodeList.some((item) => {
  429. return item === "M19";
  430. });
  431. // 查询是否有账号权限
  432. const isAccount = user.menuCodeList.some((item) => {
  433. return item === "M8";
  434. });
  435. // 查询是否有订单数据权限
  436. isOrderData.value = user.menuCodeList.some((item) => {
  437. return item === "M4";
  438. })
  439. // 查询是否有订单导出权限
  440. // const isOrderExport = user.menuCodeList.some((item) => {
  441. // return item === "M9";
  442. // })
  443. // 查询是否有数据概览权限
  444. const isDataOverview = user.menuCodeList.some((item) => {
  445. return item === "M14";
  446. })
  447. // 如果没有apk管理
  448. if (!isApkMan) {
  449. // 如果是公司人,要把apk添加上去
  450. // if (user.type === 0 || user.type === 1) {
  451. // pushToolList.value.push({
  452. // label: t("home.apkMan"),
  453. // value: "M19"
  454. // });
  455. // }
  456. }
  457. // 如果没有账号权限
  458. if (!isAccount) {
  459. // 如果是公司人type=0,要把账号权限添加上去
  460. if (user.type === 0) {
  461. pushToolList.value.push({
  462. label: t("home.accountPermission"),
  463. value: "M8"
  464. });
  465. }
  466. }
  467. // 子商家以上级别,默认可以看到订单详情
  468. if (user.type === 0 || user.type === 2) {
  469. showDataDiv.value = true;
  470. } else {
  471. // 如果有数据概览权限 和 订单数据权限
  472. if (isDataOverview && isOrderData.value) {
  473. showDataDiv.value = true;
  474. }
  475. }
  476. };
  477. // 常用操作跳转页面
  478. const pushToolPage = (index) => {
  479. // console.log("常用操作跳转页面menuList >>> " + menuList);
  480. switch (index) {
  481. case "M1":
  482. router.push({ path: "/device" }); // 设备管理
  483. break;
  484. case "M3":
  485. // router.push({ path: "/distributionSet" });
  486. router.push({ path: "/accountOperation" }); // 账户操作
  487. break;
  488. case "M4":
  489. router.push({ path: "/orderCenter" }); // 订单数据
  490. break;
  491. case "M5":
  492. router.push({ path: "/advertManage" }); // 广告管理
  493. break;
  494. case "M6":
  495. router.push({ path: "/taskMessage" });
  496. break;
  497. case "M7":
  498. router.push({ path: "/discountCode" });
  499. break;
  500. case "M8":
  501. router.push({ path: "/accountPer" });
  502. break;
  503. case "M9":
  504. router.push({ path: "/orderExport" });
  505. break;
  506. case "M10":
  507. router.push({ path: "/subLedgerManage" });
  508. break;
  509. case "M11":
  510. router.push({ path: "/robotranking" });
  511. break;
  512. case "M12":
  513. router.push({ path: "/joinpayMch" });
  514. break;
  515. case "M13":
  516. router.push({ path: "/shandeMch" });
  517. break;
  518. case "M15":
  519. router.push({ path: "/alarmHistory" }); // 报警历史
  520. break;
  521. case "M18":
  522. router.push({ path: "/labelMan" });
  523. break;
  524. case "M19":
  525. router.push({ path: "/apkManage" });
  526. break;
  527. case "M20":
  528. router.push({ path: "/merchantManage" });
  529. break;
  530. }
  531. };
  532. // 如果是空数据
  533. const noData = (volumes, nums) => {
  534. if (!volumes && !nums) {
  535. return true;
  536. }
  537. return false;
  538. };
  539. // 显示logo
  540. const showLogo = (url) => {
  541. return require(`../../assets/home/${url}.png`);
  542. };
  543. return {
  544. userName,
  545. update,
  546. upselectdata,
  547. chartBox,
  548. pushOrderCenter,
  549. pushToolList,
  550. pushToolPage,
  551. salesVolume,
  552. salesNumber,
  553. orderNumber,
  554. sys,
  555. noticeClk,
  556. confirmClk,
  557. kDialogRef,
  558. noData,
  559. equipStatus,
  560. noticeContent,
  561. showLogo,
  562. dateSelect,
  563. Format_time,
  564. showDataDiv,
  565. currencySymbol,
  566. };
  567. },
  568. };
  569. </script>
  570. <style lang="less" scoped>
  571. @import "../../common/style/common";
  572. </style>