index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. <template>
  2. <view class="fix-top-window">
  3. <view class="uni-header">
  4. <uni-stat-breadcrumb class="uni-stat-breadcrumb-on-phone" />
  5. <view class="uni-group">
  6. <view class="uni-sub-title hide-on-phone"></view>
  7. </view>
  8. </view>
  9. <view class="uni-container">
  10. <uni-notice-bar v-if="!deviceTableData.length && !userTableData.length && !query.platform_id" showGetMore
  11. showIcon class="mb-m pointer" text="暂无数据, 统计相关功能需开通 uni 统计后才能使用, 如未开通, 点击查看具体流程"
  12. @click="navTo('https://uniapp.dcloud.io/uni-stat-v2.html')" />
  13. <view class="uni-stat--x mb-m">
  14. <uni-stat-tabs label="平台选择" type="boldLine" mode="platform" v-model="query.platform_id" />
  15. </view>
  16. <!-- <uni-stat-panel :items="panelData" :contrast="true" /> -->
  17. <view class="uni-stat--x p-m">
  18. <view class="uni-stat-card-header">设备概览</view>
  19. <uni-table :loading="loading" border stripe emptyText="暂无数据">
  20. <uni-tr>
  21. <!-- <uni-th align="center">操作</uni-th> -->
  22. <template v-for="(mapper, index) in deviceTableFields">
  23. <uni-th v-if="mapper.title" :key="index" align="center">
  24. {{mapper.title}}
  25. </uni-th>
  26. </template>
  27. </uni-tr>
  28. <uni-tr v-for="(item ,i) in deviceTableData" :key="i">
  29. <template v-for="(mapper, index) in deviceTableFields">
  30. <uni-td v-if="mapper.field === 'appid'" align="center">
  31. <view v-if="item.appid" @click="navTo('/pages/uni-stat/device/overview/overview', item.appid)"
  32. class="link-btn-color">
  33. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  34. </view>
  35. <view v-else @click="navTo('/pages/system/app/add')" class="link-btn-color">
  36. 需添加此应用的 appid
  37. </view>
  38. </uni-td>
  39. <uni-td v-else :key="index" align="center">
  40. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  41. </uni-td>
  42. </template>
  43. </uni-tr>
  44. </uni-table>
  45. </view>
  46. <view class="uni-stat--x p-m">
  47. <view class="uni-stat-card-header">注册用户概览</view>
  48. <uni-table :loading="loading" border stripe emptyText="暂无数据">
  49. <uni-tr>
  50. <template v-for="(mapper, index) in userTableFields">
  51. <uni-th v-if="mapper.title" :key="index" align="center">
  52. {{mapper.title}}
  53. </uni-th>
  54. </template>
  55. </uni-tr>
  56. <uni-tr v-for="(item ,i) in userTableData" :key="i">
  57. <template v-for="(mapper, index) in userTableFields">
  58. <uni-td v-if="mapper.field === 'appid'" align="center">
  59. <view v-if="item.appid" @click="navTo('/pages/uni-stat/user/overview/overview', item.appid)"
  60. class="link-btn-color">
  61. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  62. </view>
  63. <view v-else @click="navTo('/pages/system/app/add')" class="link-btn-color">
  64. 需添加此应用的 appid
  65. </view>
  66. </uni-td>
  67. <uni-td v-else :key="index" align="center">
  68. {{item[mapper.field] !== undefined ? item[mapper.field] : '-'}}
  69. </uni-td>
  70. </template>
  71. </uni-tr>
  72. </uni-table>
  73. </view>
  74. <!-- <view class="uni-pagination-box">
  75. <uni-pagination show-icon :page-size="pageSize" :current="pageCurrent" :total="tableData.length" />
  76. </view> -->
  77. </view>
  78. <!-- #ifndef H5 -->
  79. <fix-window />
  80. <!-- #endif -->
  81. </view>
  82. </template>
  83. <script>
  84. import {
  85. stringifyQuery,
  86. stringifyField,
  87. stringifyGroupField,
  88. getTimeOfSomeDayAgo,
  89. division,
  90. format,
  91. parseDateTime,
  92. getFieldTotal
  93. } from '@/js_sdk/uni-stat/util.js'
  94. import {
  95. deviceFeildsMap,
  96. userFeildsMap
  97. } from './fieldsMap.js'
  98. export default {
  99. data() {
  100. return {
  101. query: {
  102. platform_id: '',
  103. start_time: [getTimeOfSomeDayAgo(1), new Date().getTime()]
  104. },
  105. deviceTableData: [],
  106. userTableData: [],
  107. // panelData: panelOption,
  108. // 每页数据量
  109. pageSize: 10,
  110. // 当前页
  111. pageCurrent: 1,
  112. // 数据总量
  113. total: 0,
  114. loading: false,
  115. // fieldsMap,
  116. }
  117. },
  118. onReady() {
  119. this.getApps(this.queryStr, deviceFeildsMap, 'device')
  120. this.getApps(this.queryStr, userFeildsMap, 'user')
  121. },
  122. watch: {
  123. query: {
  124. deep: true,
  125. handler(newVal) {
  126. this.getApps(this.queryStr, deviceFeildsMap, 'device')
  127. this.getApps(this.queryStr, userFeildsMap, 'user')
  128. }
  129. }
  130. },
  131. computed: {
  132. queryStr() {
  133. const defQuery = `(dimension == "hour" || dimension == "day")`
  134. return stringifyQuery(this.query) + ' && ' + defQuery
  135. },
  136. deviceTableFields() {
  137. return this.tableFieldsMap(deviceFeildsMap)
  138. },
  139. userTableFields() {
  140. return this.tableFieldsMap(userFeildsMap)
  141. }
  142. },
  143. methods: {
  144. tableFieldsMap(fieldsMap) {
  145. let tableFields = []
  146. const today = []
  147. const yesterday = []
  148. const other = []
  149. for (const mapper of fieldsMap) {
  150. if (mapper.field) {
  151. if (mapper.hasOwnProperty('value')) {
  152. const t = JSON.parse(JSON.stringify(mapper))
  153. const y = JSON.parse(JSON.stringify(mapper))
  154. if (mapper.field !== 'total_users' && mapper.field !== 'total_devices') {
  155. t.title = '今日' + mapper.title
  156. t.field = mapper.field + '_value'
  157. y.title = '昨日' + mapper.title
  158. y.field = mapper.field + '_contrast'
  159. today.push(t)
  160. yesterday.push(y)
  161. } else {
  162. t.field = mapper.field + '_value'
  163. other.push(t)
  164. }
  165. } else {
  166. tableFields.push(mapper)
  167. }
  168. }
  169. }
  170. tableFields = [...tableFields, ...today, ...yesterday, ...other]
  171. return tableFields
  172. },
  173. getApps(query, fieldsMap, type = "device") {
  174. this.loading = true
  175. const db = uniCloud.database()
  176. const appList = db.collection('opendb-app-list').getTemp()
  177. const appDaily = db.collection('uni-stat-result')
  178. .where(query)
  179. .getTemp()
  180. db.collection(appDaily, appList)
  181. .field(
  182. `${stringifyField(fieldsMap, '', 'value')},stat_date,appid,dimension`
  183. )
  184. .groupBy(`appid,dimension,stat_date`)
  185. .groupField(stringifyGroupField(fieldsMap, '', 'value'))
  186. .orderBy(`appid`, 'desc')
  187. .get()
  188. .then((res) => {
  189. let {
  190. data
  191. } = res.result
  192. this[`${type}TableData`] = []
  193. if (!data.length) return
  194. let appids = [],
  195. todays = [],
  196. yesterdays = [],
  197. isToday = parseDateTime(getTimeOfSomeDayAgo(0), '', ''),
  198. isYesterday = parseDateTime(getTimeOfSomeDayAgo(1), '', '')
  199. for (const item of data) {
  200. const {
  201. appid,
  202. name
  203. } = item.appid && item.appid[0] || {}
  204. item.appid = appid
  205. item.name = name
  206. if (appids.indexOf(item.appid) < 0) {
  207. appids.push(item.appid)
  208. }
  209. if (item.dimension === 'hour' && item.stat_date === isToday) {
  210. todays.push(item)
  211. }
  212. if (item.dimension === 'day' && item.stat_date === isYesterday) {
  213. yesterdays.push(item)
  214. }
  215. }
  216. const keys = fieldsMap.map(f => f.field).filter(Boolean)
  217. for (const appid of appids) {
  218. const rowData = {}
  219. const t = todays.find(item => item.appid === appid)
  220. const y = yesterdays.find(item => item.appid === appid)
  221. for (const key of keys) {
  222. if (key === 'appid' || key === 'name') {
  223. rowData[key] = t && t[key]
  224. } else {
  225. const value = t && t[key]
  226. const contrast = y && y[key]
  227. rowData[key + '_value'] = format(value)
  228. rowData[key + '_contrast'] = format(contrast)
  229. }
  230. }
  231. this[`${type}TableData`].push(rowData)
  232. if (appid) {
  233. // total_users 不准确,置空后由 getFieldTotal 处理, appid 不存在时暂不处理
  234. t[`total_${type}s`] = 0
  235. const query = JSON.parse(JSON.stringify(this.query))
  236. query.start_time = [getTimeOfSomeDayAgo(0), new Date().getTime()]
  237. query.appid = appid
  238. getFieldTotal.call(this, query, `total_${type}s`).then(total => {
  239. this[`${type}TableData`].find(item => item.appid === appid)[
  240. `total_${type}s_value`] = total
  241. })
  242. }
  243. }
  244. }).catch((err) => {
  245. console.error(err)
  246. // err.message 错误信息
  247. // err.code 错误码
  248. }).finally(() => {
  249. this.loading = false
  250. })
  251. },
  252. navTo(url, id) {
  253. if (url.indexOf('http') > -1) {
  254. window.open(url)
  255. } else {
  256. if (id) {
  257. url = `${url}?appid=${id}`
  258. }
  259. uni.navigateTo({
  260. url
  261. })
  262. }
  263. }
  264. }
  265. }
  266. </script>
  267. <style>
  268. .uni-stat-card-header {
  269. display: flex;
  270. justify-content: space-between;
  271. color: #555;
  272. font-size: 14px;
  273. font-weight: 600;
  274. padding: 10px 0;
  275. margin-bottom: 15px;
  276. }
  277. .uni-table-scroll {
  278. min-height: auto;
  279. }
  280. .link-btn-color {
  281. color: #007AFF;
  282. cursor: pointer;
  283. }
  284. </style>