index.vue 19 KB

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