li.shaoyi 2 лет назад
Родитель
Сommit
dce96fab4e

+ 2 - 2
public/manifest.json

@@ -143,7 +143,7 @@
                 "permissions" : [],
                 "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
                 "autoSdkPermissions" : false,
-                "minSdkVersion" : 29
+                "minSdkVersion" : 23
             },
             /*使用Native.js调用原生安卓API需要使用到的系统权限*/
             "orientation" : [ "portrait-primary" ],
@@ -274,7 +274,7 @@
                     "xxhdpi" : "../src/packages/mobile/assets/images/boot-1080p.png" /*1080P高分屏启动图片,分辨率:1080x1882*/
                 },
                 "androidStyle" : "default",
-                "iosStyle" : "storyboard",
+                "iosStyle" : "common",
                 "useOriginalMsgbox" : true
             },
             "plugins" : {

+ 5 - 1
src/packages/mobile/components/base/list/index.vue

@@ -4,7 +4,7 @@
             <!-- <colgroup>
                 <col :width="colWidth" v-for="i in columns.length" :key="i" />
             </colgroup> -->
-            <thead class="app-list__header">
+            <thead class="app-list__header" v-if="showHeader">
                 <tr class="app-list__row">
                     <th class="app-list__column" v-for="(column, i) in columns" :key="i">
                         <div class="app-list__cell">{{ column.label }}</div>
@@ -40,6 +40,10 @@ defineProps({
         type: Array as PropType<Model.TableColumn[]>,
         required: true,
     },
+    showHeader: {
+        type: Boolean,
+        default: true
+    }
 })
 
 const emit = defineEmits(['click'])

+ 5 - 0
src/packages/mobile/router/index.ts

@@ -125,6 +125,11 @@ const routes: Array<RouteRecordRaw> = [
         name: "Market",
         component: () => import("../views/market/list/index.vue"),
       },
+      {
+        path: "spot",
+        name: "MarketSpot",
+        component: () => import("../views/market/spot/index.vue"),
+      },
     ],
   },
   {

+ 2 - 5
src/packages/mobile/views/home/components/main/index.vue

@@ -44,7 +44,7 @@
         </ul>
       </app-block>
       <app-block class="home-main__market" v-if="spotQuoteList.length">
-        <Cell class="home-main__titlebar" value="更多" :to="{ name: 'Market' }" is-link>
+        <Cell class="home-main__titlebar" value="更多" :to="{ name: 'MarketSpot' }" is-link>
           <template #title>
             <img src="@mobile/assets/icons/spot.png" />
             <span>现货行情</span>
@@ -149,10 +149,7 @@ const currentSpotQuote = computed(() => spotQuoteList.value[spotQuoteIndex.value
 // 打开新闻详情
 const openNewsDetails = (id: number) => {
   if (id) {
-    const details = newsList.value.find((e) => e.id === id)
-    if (details) {
-      router.push({ name: 'news-details', query: { id: details.id } })
-    }
+    router.push({ name: 'news-details', query: { id } })
   }
 }
 

+ 36 - 18
src/packages/mobile/views/home/index.vue

@@ -8,7 +8,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, onActivated, onMounted } from 'vue'
+import { shallowRef, onActivated, onMounted, onUnmounted } from 'vue'
 import { fullloading, dialog } from '@/utils/vant'
 import { Tabbar } from '@mobile/components/base/tabbar/interface'
 import { GetAppUpdateInfo } from '@/services/api/common'
@@ -81,19 +81,33 @@ const onTabClick = ({ name }: Tabbar, index: number) => {
 }
 
 // 版本号转数值
-// const versionToNumber = (value: number | string) => {
-//   if (value) {
-//     const num = value.toString().split(/\D/)
-//     // 版本号位数
-//     const place = ['', '0', '00', '000', '0000', '00000', '000000'].reverse()
-//     for (let i = 0; i < num.length; i++) {
-//       const len = num[i].length
-//       num[i] = place[len] + num[i]
-//     }
-//     return +num.join('')
-//   }
-//   return 0
-// }
+const versionToNumber = (value: number | string) => {
+  if (value) {
+    const num = value.toString().split(/\D/)
+    // 版本号位数
+    const place = ['', '0', '00', '000', '0000', '00000', '000000'].reverse()
+    for (let i = 0; i < num.length; i++) {
+      const len = num[i].length
+      num[i] = place[len] + num[i]
+    }
+    return +num.join('')
+  }
+  return 0
+}
+
+const ondownload = plus.onDownload((filename: string, progress: number) => {
+  if (progress === 100) {
+    dialog({
+      message: '新版本下载完成,是否安装?',
+      showCancelButton: true,
+      confirmButtonText: '安装'
+    }).then(() => {
+      plus.installApp(filename)
+    }).catch(() => {
+      plus.deleteFile(filename)
+    })
+  }
+})
 
 onMounted(() => {
   const os = plus.getSystemInfo('os')
@@ -108,11 +122,11 @@ onMounted(() => {
         const { LastVersionCode, ApkUrl } = data[0] as Model.AppUpdateInfo
         if (Number(LastVersionCode) > Number(currentVersionCode)) {
           dialog({
-            message: '发现新版本,是否更新?',
+            message: '发现新版本,是否下载?',
             showCancelButton: true,
-            confirmButtonText: '更新'
+            confirmButtonText: '下载'
           }).then(() => {
-            plus.updateApp(ApkUrl)
+            plus.createDownload(ApkUrl)
           })
         }
       }
@@ -126,7 +140,7 @@ onMounted(() => {
       const results = res.data.results
       if (results?.length) {
         const { version, trackViewUrl } = results[0]
-        if (version !== currentVersion) {
+        if (versionToNumber(version) > versionToNumber(currentVersion)) {
           dialog({
             message: '发现新版本,是否更新?',
             showCancelButton: true,
@@ -140,6 +154,10 @@ onMounted(() => {
   }
 })
 
+onUnmounted(() => {
+  ondownload.cancel()
+})
+
 onActivated(() => {
   const { tabName, showLogin } = getGlobalUrlParams()
   const index = tabList.findIndex((e) => e.name === tabName)

+ 15 - 0
src/packages/mobile/views/market/spot/index.less

@@ -0,0 +1,15 @@
+.market-spot {
+    .app-list {
+        background-color: transparent;
+
+        &__row {
+            &:after {
+                border-bottom: 1px solid #ddd;
+            }
+
+            .text-red {
+                color: var(--color-up);
+            }
+        }
+    }
+}

+ 68 - 0
src/packages/mobile/views/market/spot/index.vue

@@ -0,0 +1,68 @@
+<template>
+    <app-view class="market-spot">
+        <template #header>
+            <app-navbar title="现货行情" />
+        </template>
+        <Tabs @change="onTabChange" v-model:active="active">
+            <template v-for="(item, index) in tabList" :key="index">
+                <Tab :name="item.spotname" :title="item.spotname" />
+            </template>
+        </Tabs>
+        <template v-if="dataList.length">
+            <app-list :columns="columns" :data-list="dataList" :showHeader="false" @click="onRowClick">
+                <template #spotprice="{ value }">
+                    <span class="text-red">{{ value }} 元/吨</span>
+                </template>
+                <template #spotqty="{ value }">
+                    <span class="text-red">{{ value }} 吨</span>
+                </template>
+            </app-list>
+        </template>
+        <Empty v-else />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { Tab, Tabs, Empty } from 'vant'
+import { useNavigation } from '@/hooks/navigation'
+import { useRequest } from '@/hooks/request'
+import { queryThjSpotQuote, queryThjSpotQuoteConfig } from '@/services/api/market'
+import AppList from '@mobile/components/base/list/index.vue'
+
+const { router } = useNavigation()
+const active = shallowRef(0)
+
+const { dataList, run } = useRequest(queryThjSpotQuoteConfig, {
+    manual: true
+})
+
+const { dataList: tabList } = useRequest(queryThjSpotQuote, {
+    onSuccess: (res) => {
+        if (res.data) {
+            run({ spotname: res.data[0].spotname })
+        }
+    }
+})
+
+const columns: Model.TableColumn[] = [
+    { prop: 'spotmonth', label: '月份' },
+    { prop: 'spotsrc', label: '来源' },
+    { prop: 'spotprice', label: '价格' },
+    { prop: 'spotqty', label: '数量' },
+]
+
+const onTabChange = (spotname: string) => {
+    run({ spotname })
+}
+
+const onRowClick = (row: Model.ThjSpotQuoteConfigRsp) => {
+    if (row.relatedid) {
+        router.push({ name: 'news-details', query: { id: row.relatedid } })
+    }
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 11 - 1
src/services/api/market/index.ts

@@ -23,8 +23,18 @@ export function querySpotgoodsPrice(params: Model.SpotgoodsPriceReq) {
 /**
  * 查询现货行情配置表
  */
-export function queryThjSpotQuoteConfig() {
+export function queryThjSpotQuote() {
+    return http.commonRequest<Model.ThjSpotQuoteRsp[]>({
+        url: '/Ferroalloy/QueryThjSpotQuote',
+    })
+}
+
+/**
+ * 查询现货行情配置表
+ */
+export function queryThjSpotQuoteConfig(params?: Model.ThjSpotQuoteConfigReq) {
     return http.commonRequest<Model.ThjSpotQuoteConfigRsp[]>({
         url: '/Ferroalloy/QueryThjSpotQuoteConfig',
+        params,
     })
 }

+ 11 - 11
src/services/bus/index.ts

@@ -8,7 +8,7 @@ export default new (class {
     private eventMap = new Map<string, EventMessage>();
 
     /** 订阅事件 */
-    $on(eventKey: keyof typeof EventKey | (keyof typeof EventKey)[], callback: EventMessage['callback']) {
+    $on(eventKey: EventKey | EventKey[], callback: EventMessage['callback']) {
         const uuid = v4();
         const keys = Array.isArray(eventKey) ? eventKey : [eventKey];
 
@@ -25,24 +25,24 @@ export default new (class {
     }
 
     /** 触发事件 */
-    $emit(eventKey: keyof typeof EventKey, data?: unknown) {
-        for (const message of this.eventMap.values()) {
-            if (message.keys.includes(eventKey)) {
-                message.callback(data);
+    $emit(eventKey: EventKey, data?: unknown) {
+        for (const e of this.eventMap.values()) {
+            if (e.keys.includes(eventKey)) {
+                e.callback(data);
             }
         }
     }
 
     /** 取消事件 */
-    $off(...eventkeys: (keyof typeof EventKey)[]) {
+    $off(...eventkeys: EventKey[]) {
         if (eventkeys.length) {
-            for (const [uuid, message] of this.eventMap.entries()) {
-                for (let i = message.keys.length - 1; i >= 0; i--) {
-                    if (eventkeys.includes(message.keys[i])) {
-                        message.keys.splice(i, 1);
+            for (const [uuid, e] of this.eventMap.entries()) {
+                for (let i = e.keys.length - 1; i >= 0; i--) {
+                    if (eventkeys.includes(e.keys[i])) {
+                        e.keys.splice(i, 1);
                     }
                 }
-                if (!message.keys.length) {
+                if (!e.keys.length) {
                     this.eventMap.delete(uuid);
                 }
             }

+ 8 - 3
src/services/bus/interface.ts

@@ -1,7 +1,7 @@
 /**
- * 事件key
+ * 事件
  */
-export enum EventKey {
+export enum EventCode {
     QuotePushNotify, // 行情推送通知
     QuoteServerReconnectNotify, // 行情服务重连成功通知
     LoginNotify, // 用户登入通知
@@ -13,9 +13,14 @@ export enum EventKey {
 }
 
 /**
+ * 事件key
+ */
+export type EventKey = keyof typeof EventCode
+
+/**
  * 事件消息
  */
 export interface EventMessage {
-    keys: (keyof typeof EventKey)[];
+    keys: EventKey[];
     callback: (data: unknown) => void;
 }

+ 10 - 0
src/types/model/market.d.ts

@@ -1,4 +1,14 @@
 declare namespace Model {
+    /** 查询现货行情配置列表 响应 */
+    interface ThjSpotQuoteRsp {
+        spotname: string; // 现货名称
+    }
+
+    /** 查询现货行情配置表 请求 */
+    interface ThjSpotQuoteConfigReq {
+        spotname?: string; // 现货名称
+    }
+
     /** 查询现货行情配置表 响应 */
     interface ThjSpotQuoteConfigRsp {
         autoid: number;  // 自增ID(SEQ_THJ_SPOTQUOTECONFIG)

+ 42 - 0
src/utils/h5plus/constants.ts

@@ -0,0 +1,42 @@
+export const urlScheme = {
+    appStore: {
+        name: 'App Store',
+        pname: '',
+        scheme: 'itms-apps://'
+    },
+    alipay: {
+        name: '支付宝',
+        pname: 'com.eg.android.AlipayGphone',
+        scheme: 'alipay://'
+    },
+    taobao: {
+        name: '淘宝',
+        pname: 'com.taobao.taobao',
+        scheme: 'taobao://'
+    },
+    qq: {
+        name: 'QQ',
+        pname: 'com.tencent.mobileqq',
+        scheme: 'mqq://'
+    },
+    weixin: {
+        name: '微信',
+        pname: 'com.tencent.mm',
+        scheme: 'weixin://'
+    },
+    jd: {
+        name: '京东',
+        pname: 'com.jingdong.app.mall',
+        scheme: 'openApp.jdMobile://'
+    },
+    weibo: {
+        name: '新浪微博',
+        pname: 'com.sina.weibo',
+        scheme: 'sinaweibo://'
+    },
+    youku: {
+        name: '优酷',
+        pname: 'com.youku.phone',
+        scheme: 'youku://'
+    }
+}

+ 88 - 104
src/utils/h5plus/index.ts

@@ -1,5 +1,7 @@
 /* eslint-disable */
+import { v4 } from 'uuid'
 import { SystemInfo, ShareMessage, HttpRequestConfig } from './interface'
+import { urlScheme } from './constants'
 
 declare global {
     interface Window {
@@ -7,49 +9,6 @@ declare global {
     }
 }
 
-const urlScheme = {
-    appStore: {
-        name: 'App Store',
-        pname: '',
-        scheme: 'itms-apps://'
-    },
-    alipay: {
-        name: '支付宝',
-        pname: 'com.eg.android.AlipayGphone',
-        scheme: 'alipay://'
-    },
-    taobao: {
-        name: '淘宝',
-        pname: 'com.taobao.taobao',
-        scheme: 'taobao://'
-    },
-    qq: {
-        name: 'QQ',
-        pname: 'com.tencent.mobileqq',
-        scheme: 'mqq://'
-    },
-    weixin: {
-        name: '微信',
-        pname: 'com.tencent.mm',
-        scheme: 'weixin://'
-    },
-    jd: {
-        name: '京东',
-        pname: 'com.jingdong.app.mall',
-        scheme: 'openApp.jdMobile://'
-    },
-    weibo: {
-        name: '新浪微博',
-        pname: 'com.sina.weibo',
-        scheme: 'sinaweibo://'
-    },
-    youku: {
-        name: '优酷',
-        pname: 'com.youku.phone',
-        scheme: 'youku://'
-    }
-}
-
 export default new (class {
     private readonly plusready = new Promise<void>((resolve) => {
         if (this.hasPlus()) {
@@ -65,6 +24,11 @@ export default new (class {
     private xhr = new XMLHttpRequest()
 
     /**
+     * 当前下载任务
+     */
+    private downloadTask = new Map()
+
+    /**
      * 系统信息
      */
     private systemInfo: SystemInfo = {
@@ -124,15 +88,6 @@ export default new (class {
     }
 
     /**
-     * 退出应用程序
-     */
-    quit() {
-        this.onPlusReady((plus) => {
-            plus.runtime.quit()
-        })
-    }
-
-    /**
      * 获取系统信息
      * @param prop 
      * @returns 
@@ -234,64 +189,93 @@ export default new (class {
     }
 
     /**
-     * 更新应用
+     * 删除文件
      * @param url 
      */
-    updateApp(url: string) {
+    deleteFile(url: string) {
         this.onPlusReady((plus) => {
-            const dtask = plus.downloader.createDownload(
-                url,
-                {
-                    filename: ''
-                },
-                function (d: { filename: string }, status: number) {
-                    if (status == 200) {
-                        // 当前下载的状态
-                        installApp(d.filename) // 调用安装的方法
-                    } else {
-                        //plus.nativeUI.alert('下载失败')
-                    }
-                }
-            )
-
-            dtask.start() // 开启下载的任务
-            // app自动更新进度
-            dtask.addEventListener('statechanged', function (task: { state: number }) {
-                // 给下载任务设置一个监听 并根据状态  做操作
-                switch (task.state) {
-                    case 1:
-                        console.log('正在下载')
-                        break
-                    case 2:
-                        console.log('已连接到服务器')
-                        break
-                    case 3:
-                    // console.log(task)
-                    // console.log(task.downloadedSize)//当前的大
-                    // console.log(task.totalSize)//安装包的大小
+            plus.io.resolveLocalFileSystemURL(url, (entry: any) => {
+                entry.remove()
+            })
+        })
+    }
+
+    /**
+     * 监听下载进度
+     * @param callback 
+     * @returns 
+     */
+    onDownload(callback: (filename: string, progress: number) => void) {
+        const uuid = v4()
+        this.downloadTask.set(uuid, callback)
+
+        /** 注意离开页面时销毁监听事件,防止事件重复触发 */
+        return {
+            uuid,
+            cancel: () => this.downloadTask.delete(uuid)
+        }
+    }
+
+    /**
+     * 文件下载
+     * https://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.createDownload
+     * @param url 
+     */
+    createDownload(url: string) {
+        this.onPlusReady((plus) => {
+            plus.downloader.enumerate((downloads: any) => {
+                if (downloads.length) {
+                    plus.nativeUI.toast('正在下载')
+                } else {
+                    const task = plus.downloader.createDownload(url, {
+                        filename: '_downloads/', // 非系统 Download 目录
+                        retry: 1,
+                    }, (d: any, status: number) => {
+                        if (status !== 200) {
+                            plus.nativeUI.toast('下载失败')
+                        }
+                    })
+                    // 监听下载状态
+                    task.addEventListener('statechanged', (task: any) => {
+                        switch (task.state) {
+                            case 3:
+                                const progress = task.downloadedSize / task.totalSize * 100
+                                for (const fn of this.downloadTask.values()) {
+                                    fn(task.filename, progress) // 推送下载进度
+                                }
+                                break
+                            case 4:
+                                console.log('下载完成', task.filename)
+                                this.downloadTask.clear()
+                                break
+                        }
+                    })
+                    // 开始下载
+                    task.start()
                 }
             })
+        })
+    }
 
-            // 自动更新
-            function installApp(path: string) {
-                plus.nativeUI.showWaiting('正在更新...')
-                plus.runtime.install(
-                    path,
-                    {
-                        // true表示强制安装,不进行版本号的校验;false则需要版本号校验,如果将要安装应用的版本号不高于现有应用的版本号则终止安装,并返回安装失败。 仅安装wgt和wgtu时生效,默认值 false
-                        force: false
-                    },
-                    function () {
-                        plus.nativeUI.closeWaiting()
-                        console.log('更新成功!')
-                        plus.runtime.restart()
-                    },
-                    function (e: { message: string }) {
-                        plus.nativeUI.closeWaiting()
-                        plus.nativeUI.alert('更新失败:' + e.message)
-                    }
-                )
-            }
+    /**
+     * App更新安装
+     * @param file 
+     */
+    installApp(file: string) {
+        this.onPlusReady((plus) => {
+            plus.nativeUI.showWaiting('正在安装...')
+            plus.runtime.install(file, {
+                // true表示强制安装,不进行版本号的校验;false则需要版本号校验,如果将要安装应用的版本号不高于现有应用的版本号则终止安装,并返回安装失败。 仅安装wgt和wgtu时生效,默认值 false
+                force: false
+            }, () => {
+                console.log('安装成功!')
+                this.deleteFile(file)
+                plus.nativeUI.closeWaiting()
+                plus.runtime.restart()
+            }, (e: any) => {
+                plus.nativeUI.closeWaiting()
+                plus.nativeUI.alert('安装失败:' + e.message)
+            })
         })
     }