index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <template>
  2. <view class="fix-top-window">
  3. <view class="uni-header">
  4. <!-- 统计面包屑 -->
  5. <uni-stat-breadcrumb class="uni-stat-breadcrumb-on-phone" />
  6. <view class="uni-group">
  7. <view class="uni-sub-title hide-on-phone"></view>
  8. </view>
  9. </view>
  10. <view class="uni-container">
  11. <!-- 提示条1:初始化db_init.json -->
  12. <uni-notice-bar v-if="showdbInit" showGetMore showIcon class="mb-m pointer" text="检测到您未初始化db_init.json,请先右键uniCloud/database/db_init.json文件,执行初始化云数据库,否则左侧无法显示菜单等数据" background-color="#fef0f0" color="#f56c6c" @click="toAddAppId" />
  13. <!-- 提示条2:添加应用 -->
  14. <uni-notice-bar v-if="showAddAppId" showGetMore showIcon class="mb-m pointer" text="检测到您还未添加应用,点击前往应用管理添加" @click="toAddAppId" />
  15. <!-- 提示条3:暂无数据,需开通统计功能 -->
  16. <uni-notice-bar v-if="!deviceTableData.length && !userTableData.length && !query.platform_id && complete" showGetMore showIcon class="mb-m pointer"
  17. text="暂无数据, 统计相关功能需开通 uni 统计后才能使用, 如未开通, 点击查看具体流程" @click="navTo('https://uniapp.dcloud.io/uni-stat-v2.html')" />
  18. <view class="uni-stat--x mb-m">
  19. <!-- 平台选择标签 -->
  20. <uni-stat-tabs label="平台选择" type="boldLine" mode="platform" v-model="query.platform_id" />
  21. </view>
  22. <view class="uni-stat--x p-m">
  23. <view class="uni-stat-card-header">设备概览</view>
  24. <!-- 设备概览表格 -->
  25. <uni-table :loading="loading" border stripe emptyText="暂无数据">
  26. <uni-tr>
  27. <block v-for="(mapper, index) in deviceTableFields" :key="index">
  28. <!-- 表头列 -->
  29. <uni-th v-if="mapper.title" :key="index" align="center">
  30. {{mapper.title}}
  31. </uni-th>
  32. </block>
  33. </uni-tr>
  34. <uni-tr v-for="(item ,i) in deviceTableData" :key="i">
  35. <block v-for="(mapper, index) in deviceTableFields" :key="index">
  36. <uni-td v-if="mapper.field === 'appid'" align="center">
  37. <view v-if="item.appid" @click="navTo('/pages/uni-stat/device/overview/overview', item.appid)" class="link-btn-color">
  38. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  39. </view>
  40. <view v-else @click="navTo('/pages/system/app/add')" class="link-btn-color">
  41. 需添加此应用的 appid
  42. </view>
  43. </uni-td>
  44. <uni-td v-else :key="index" align="center">
  45. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  46. </uni-td>
  47. </block>
  48. </uni-tr>
  49. </uni-table>
  50. </view>
  51. <view class="uni-stat--x p-m">
  52. <view class="uni-stat-card-header">注册用户概览</view>
  53. <!-- 注册用户概览表格 -->
  54. <uni-table :loading="loading" border stripe emptyText="暂无数据">
  55. <uni-tr>
  56. <block v-for="(mapper, index) in userTableFields" :key="index">
  57. <uni-th v-if="mapper.title" :key="index" align="center">
  58. {{mapper.title}}
  59. </uni-th>
  60. </block>
  61. </uni-tr>
  62. <uni-tr v-for="(item ,i) in userTableData" :key="i">
  63. <block v-for="(mapper, index) in userTableFields" :key="index">
  64. <uni-td v-if="mapper.field === 'appid'" align="center">
  65. <view v-if="item.appid" @click="navTo('/pages/uni-stat/user/overview/overview', item.appid)" class="link-btn-color">
  66. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  67. </view>
  68. <view v-else @click="navTo('/pages/system/app/add')" class="link-btn-color">
  69. 需添加此应用的 appid
  70. </view>
  71. </uni-td>
  72. <uni-td v-else :key="index" align="center">
  73. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  74. </uni-td>
  75. </block>
  76. </uni-tr>
  77. </uni-table>
  78. </view>
  79. </view>
  80. <!-- #ifndef H5 -->
  81. <fix-window />
  82. <!-- #endif -->
  83. </view>
  84. </template>
  85. <script>
  86. import {
  87. stringifyQuery,
  88. stringifyField,
  89. stringifyGroupField,
  90. getTimeOfSomeDayAgo,
  91. division,
  92. format,
  93. parseDateTime,
  94. getFieldTotal,
  95. debounce
  96. } from '@/js_sdk/uni-stat/util.js'
  97. import {
  98. deviceFeildsMap,
  99. userFeildsMap
  100. } from './fieldsMap.js'
  101. export default {
  102. data() {
  103. return {
  104. query: {
  105. platform_id: '',
  106. start_time: [getTimeOfSomeDayAgo(1), new Date().getTime()]
  107. },
  108. deviceTableData: [],
  109. userTableData: [],
  110. // panelData: panelOption,
  111. // 每页数据量
  112. pageSize: 10,
  113. // 当前页
  114. pageCurrent: 1,
  115. // 数据总量
  116. total: 0,
  117. loading: false,
  118. complete: false,
  119. statSetting: {
  120. mode: "",
  121. day: 7
  122. },
  123. statModeList: [
  124. { "value": "open", "text": "开启" },
  125. { "value": "close", "text": "关闭" },
  126. { "value": "auto", "text": "节能" },
  127. ],
  128. showAddAppId: false,
  129. showdbInit: false
  130. }
  131. },
  132. onReady() {
  133. // 创建一个防抖函数,延迟执行getAllData方法
  134. this.debounceGet = debounce(() => {
  135. this.getAllData(this.queryStr);
  136. }, 300);
  137. // 执行防抖函数
  138. this.debounceGet();
  139. // 检查appId
  140. this.checkAppId();
  141. this.checkdbInit();
  142. },
  143. watch: {
  144. query: {
  145. deep: true,
  146. handler(newVal) {
  147. // 监听query对象的变化,并在变化时执行防抖函数
  148. this.debounceGet(this.queryStr);
  149. }
  150. }
  151. },
  152. computed: {
  153. queryStr() {
  154. // 默认查询条件
  155. const defQuery = `(dimension == "hour" || dimension == "day")`;
  156. // 将query对象转换为查询字符串并与默认查询条件合并
  157. return stringifyQuery(this.query) + ' && ' + defQuery;
  158. },
  159. deviceTableFields() {
  160. // 返回设备表格的字段映射
  161. return this.tableFieldsMap(deviceFeildsMap);
  162. },
  163. userTableFields() {
  164. // 返回用户表格的字段映射
  165. return this.tableFieldsMap(userFeildsMap);
  166. }
  167. },
  168. methods: {
  169. getAllData(queryStr) {
  170. // 获取设备数据
  171. this.getApps(this.queryStr, deviceFeildsMap, 'device');
  172. // 获取用户数据
  173. this.getApps(this.queryStr, userFeildsMap, 'user');
  174. },
  175. tableFieldsMap(fieldsMap) {
  176. let tableFields = [];
  177. const today = [];
  178. const yesterday = [];
  179. const other = [];
  180. for (const mapper of fieldsMap) {
  181. if (mapper.field) {
  182. if (mapper.hasOwnProperty('value')) {
  183. // 如果字段映射中有'value'属性,则根据映射生成今天和昨天的字段
  184. const t = JSON.parse(JSON.stringify(mapper));
  185. const y = JSON.parse(JSON.stringify(mapper));
  186. if (mapper.field !== 'total_users' && mapper.field !== 'total_devices') {
  187. t.title = '今日' + mapper.title;
  188. t.field = mapper.field + '_value';
  189. y.title = '昨日' + mapper.title;
  190. y.field = mapper.field + '_contrast';
  191. today.push(t);
  192. yesterday.push(y);
  193. } else {
  194. t.field = mapper.field + '_value';
  195. other.push(t);
  196. }
  197. } else {
  198. // 将其他字段直接添加到tableFields中
  199. tableFields.push(mapper);
  200. }
  201. }
  202. }
  203. // 按顺序合并所有的字段
  204. tableFields = [...tableFields, ...today, ...yesterday, ...other];
  205. return tableFields;
  206. },
  207. getApps(query, fieldsMap, type = "device") {
  208. this.loading = true
  209. const db = uniCloud.database()
  210. const appDaily = db.collection('uni-stat-result').where(query).getTemp();
  211. const appList = db.collection('opendb-app-list').getTemp()
  212. db.collection(appDaily, appList)
  213. .field(
  214. `${stringifyField(fieldsMap, '', 'value')},stat_date,appid,dimension`
  215. )
  216. .groupBy(`appid,dimension,stat_date`)
  217. .groupField(stringifyGroupField(fieldsMap, '', 'value'))
  218. .orderBy(`appid`, 'desc')
  219. .get()
  220. .then((res) => {
  221. let {
  222. data
  223. } = res.result
  224. //console.log('data: ', data)
  225. this[`${type}TableData`] = []
  226. if (!data.length) return
  227. let appids = [],
  228. todays = [],
  229. yesterdays = [],
  230. isToday = parseDateTime(getTimeOfSomeDayAgo(0), '', ''),
  231. isYesterday = parseDateTime(getTimeOfSomeDayAgo(1), '', '')
  232. for (const item of data) {
  233. const {
  234. appid,
  235. name
  236. } = item.appid && item.appid[0] || {}
  237. item.appid = appid
  238. item.name = name
  239. if (appids.indexOf(item.appid) < 0) {
  240. appids.push(item.appid)
  241. }
  242. if (item.dimension === 'hour' && item.stat_date === isToday) {
  243. todays.push(item)
  244. }
  245. if (item.dimension === 'day' && item.stat_date === isYesterday) {
  246. yesterdays.push(item)
  247. }
  248. }
  249. const keys = fieldsMap.map(f => f.field).filter(Boolean)
  250. for (const appid of appids) {
  251. const rowData = {}
  252. const t = todays.find(item => item.appid === appid)
  253. const y = yesterdays.find(item => item.appid === appid)
  254. for (const key of keys) {
  255. if (key === 'appid' || key === 'name') {
  256. rowData[key] = t && t[key]
  257. } else {
  258. const value = t && t[key]
  259. const contrast = y && y[key]
  260. rowData[key + '_value'] = format(value)
  261. rowData[key + '_contrast'] = format(contrast)
  262. }
  263. }
  264. if (appid) {
  265. rowData[`total_${type}s_value`] = "获取中...";
  266. }
  267. this[`${type}TableData`].push(rowData);
  268. if (appid) {
  269. // total_users 不准确,置空后由 getFieldTotal 处理, appid 不存在时暂不处理
  270. t[`total_${type}s`] = 0
  271. const query = JSON.parse(JSON.stringify(this.query))
  272. query.start_time = [getTimeOfSomeDayAgo(0), new Date().getTime()]
  273. query.appid = appid
  274. getFieldTotal.call(this, query, `total_${type}s`).then(total => {
  275. this[`${type}TableData`].find(item => item.appid === appid)[
  276. `total_${type}s_value`] = total
  277. })
  278. }
  279. }
  280. }).catch((err) => {
  281. console.error(err)
  282. // err.message 错误信息
  283. // err.code 错误码
  284. }).finally(() => {
  285. this.loading = false;
  286. this.complete = true;
  287. })
  288. },
  289. navTo(url, id) {
  290. if (url.indexOf('http') > -1) {
  291. // 如果url中包含'http',则在新窗口中打开该链接
  292. window.open(url);
  293. } else {
  294. if (id) {
  295. // 如果有提供id参数,则将其添加到url中作为查询参数
  296. url = `${url}?appid=${id}`;
  297. }
  298. // 使用uni.navigateTo方法进行页面跳转
  299. uni.navigateTo({
  300. url
  301. });
  302. }
  303. },
  304. toUrl(url) {
  305. // #ifdef H5
  306. // 在新窗口中打开url链接(仅适用于H5平台)
  307. window.open(url, "_blank");
  308. // #endif
  309. },
  310. toAddAppId() {
  311. // 隐藏添加App ID的标识
  312. this.showAddAppId = false;
  313. // 使用uni.navigateTo方法进行页面跳转到指定路径
  314. uni.navigateTo({
  315. url: "/pages/system/app/list",
  316. events: {
  317. // 注册事件,用于在目标页面刷新数据后执行回调
  318. refreshData: () => {
  319. this.checkAppId();
  320. }
  321. }
  322. });
  323. },
  324. async checkAppId() {
  325. // 获取uniCloud数据库的实例
  326. const db = uniCloud.database();
  327. // 查询'opendb-app-list'集合的数据数量
  328. let res = await db.collection('opendb-app-list').count();
  329. // 如果查询结果为空或total为0,则显示添加App ID的标识
  330. this.showAddAppId = (!res.result || res.result.total === 0) ? true : false;
  331. },
  332. async checkdbInit(){
  333. // 获取uniCloud数据库的实例
  334. const db = uniCloud.database();
  335. // 查询'opendb-app-list'集合的数据数量
  336. let res = await db.collection('opendb-admin-menus').count();
  337. // 如果查询结果为空或total为0,则显示添加App ID的标识
  338. this.showdbInit = (!res.result || res.result.total === 0) ? true : false;
  339. if (this.showdbInit) {
  340. uni.showModal({
  341. title: "重要提示",
  342. content: `检测到您未初始化数据库,请先右键uni-admin项目根目下的 uniCloud/database 目录,执行初始化云数据库,否则左侧无法显示菜单等数据`,
  343. showCancel: false,
  344. confirmText: "我知道了"
  345. });
  346. }
  347. }
  348. }
  349. }
  350. </script>
  351. <style>
  352. .uni-stat-card-header {
  353. display: flex;
  354. justify-content: space-between;
  355. color: #555;
  356. font-size: 14px;
  357. font-weight: 600;
  358. padding: 10px 0;
  359. margin-bottom: 15px;
  360. }
  361. .uni-table-scroll {
  362. min-height: auto;
  363. }
  364. .link-btn-color {
  365. color: #007AFF;
  366. cursor: pointer;
  367. }
  368. .uni-stat-text {
  369. color: #606266;
  370. }
  371. .mt10 {
  372. margin-top: 10px;
  373. }
  374. .uni-radio-cell {
  375. margin: 0 10px;
  376. }
  377. .uni-stat-tooltip-s {
  378. width: 400px;
  379. white-space: normal;
  380. }
  381. .uni-a {
  382. cursor: pointer;
  383. text-decoration: underline;
  384. color: #555;
  385. font-size: 14px;
  386. }
  387. </style>