Przeglądaj źródła

修改UI (仍需优化表单样式)

“shengjie.huang” 1 rok temu
rodzic
commit
60e22031a9
56 zmienionych plików z 1645 dodań i 1210 usunięć
  1. 0 6
      README.md
  2. 13 0
      pages.config.ts
  3. 31 0
      src/components/icon-font/index.vue
  4. 18 19
      src/pages.json
  5. 135 157
      src/pages/assistant/index.vue
  6. 112 12
      src/pages/connect/index.vue
  7. 191 129
      src/pages/index/index.vue
  8. 112 88
      src/pages/personal/index.vue
  9. 52 0
      src/pages/personal/setting.vue
  10. 250 175
      src/pages/print/index.vue
  11. 72 90
      src/pages/print/job.vue
  12. 67 85
      src/pages/print/jobForIntranet.vue
  13. 60 78
      src/pages/printer/index.vue
  14. 0 177
      src/pages/test/index.vue
  15. 0 110
      src/pages/webview/sse.vue
  16. 112 0
      src/static/iconfont/iconfont.css
  17. 1 0
      src/static/iconfont/iconfont.js
  18. 177 0
      src/static/iconfont/iconfont.json
  19. BIN
      src/static/iconfont/iconfont.ttf
  20. BIN
      src/static/iconfont/iconfont.woff
  21. BIN
      src/static/iconfont/iconfont.woff2
  22. BIN
      src/static/images/avatar.png
  23. BIN
      src/static/images/connect.png
  24. BIN
      src/static/images/document.png
  25. BIN
      src/static/images/file.png
  26. BIN
      src/static/images/history.png
  27. BIN
      src/static/images/icon/album.png
  28. BIN
      src/static/images/icon/cards.png
  29. BIN
      src/static/images/icon/connect.png
  30. BIN
      src/static/images/icon/file.png
  31. BIN
      src/static/images/icon/folder-close.png
  32. BIN
      src/static/images/icon/folder-open.png
  33. BIN
      src/static/images/icon/history-query.png
  34. BIN
      src/static/images/icon/message.png
  35. BIN
      src/static/images/icon/picture.png
  36. BIN
      src/static/images/icon/printer-two.png
  37. BIN
      src/static/images/icon/printer.png
  38. BIN
      src/static/images/icon/wechat.png
  39. BIN
      src/static/images/invoice.png
  40. BIN
      src/static/images/logo_temp.png
  41. BIN
      src/static/images/logo_temp1.png
  42. BIN
      src/static/images/logo_top.png
  43. BIN
      src/static/images/picture.png
  44. BIN
      src/static/images/share.png
  45. BIN
      src/static/images/wechatFile.png
  46. BIN
      src/static/images/wechat_file.png
  47. BIN
      src/static/images/wechat_invoice.png
  48. 0 33
      src/static/logo.svg
  49. BIN
      src/static/tabbar/device.png
  50. BIN
      src/static/tabbar/deviceHL.png
  51. BIN
      src/static/tabbar/homeHL.png
  52. BIN
      src/static/tabbar/personalHL.png
  53. 0 28
      src/style/iconfont.css
  54. 238 17
      src/style/index.scss
  55. 3 4
      src/types/uni-pages.d.ts
  56. 1 2
      tsconfig.json

+ 0 - 6
README.md

@@ -1,9 +1,3 @@
-<p align="center">
-  <a href="https://github.com/feige996/unibest">
-    <img width="160" src="./src/static/logo.svg">
-  </a>
-</p>
-
 <h1 align="center">
   <a href="https://github.com/feige996/unibest" target="_blank">unibest - 最好的 uniapp 开发框架</a>
 </h1>

+ 13 - 0
pages.config.ts

@@ -32,6 +32,12 @@ export default defineUniPages({
         pagePath: 'pages/index/index',
         text: '首页',
       },
+      {
+        iconPath: 'static/tabbar/device.png',
+        selectedIconPath: 'static/tabbar/deviceHL.png',
+        pagePath: 'pages/assistant/index',
+        text: '设备',
+      },
       {
         iconPath: 'static/tabbar/personal.png',
         selectedIconPath: 'static/tabbar/personalHL.png',
@@ -39,5 +45,12 @@ export default defineUniPages({
         text: '我的',
       },
     ],
+    // midButton: {
+    //   width: '80px',
+    //   height: '80px',
+    //   iconPath: 'static/tabbar/deviceHL.png',
+    //   iconWidth: '50px',
+    //   text: '设备',
+    // }
   },
 })

+ 31 - 0
src/components/icon-font/index.vue

@@ -0,0 +1,31 @@
+<template>
+  <svg
+    class="icon"
+    aria-hidden="true"
+    :style="{ 
+      fontSize: size + 'rpx', 
+      color: color 
+    }"
+  >
+    <use :xlink:href="`#${prefix}${name}`" />
+  </svg>
+</template>
+
+<script setup>
+defineProps({
+  name: { type: String, required: true },  // 图标名(如 'home')
+  size: { type: [Number, String], default: 32 }, // 单位 rpx
+  color: { type: String, default: '#333' }, // 颜色
+  prefix: { type: String, default: 'icon-' } // 前缀(与 iconfont 的 symbol id 匹配)
+});
+</script>
+
+<style scoped>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor; /* 继承父级颜色 */
+  overflow: hidden;
+}
+</style>

+ 18 - 19
src/pages.json

@@ -29,6 +29,12 @@
         "pagePath": "pages/index/index",
         "text": "首页"
       },
+      {
+        "iconPath": "static/tabbar/device.png",
+        "selectedIconPath": "static/tabbar/deviceHL.png",
+        "pagePath": "pages/assistant/index",
+        "text": "设备"
+      },
       {
         "iconPath": "static/tabbar/personal.png",
         "selectedIconPath": "static/tabbar/personalHL.png",
@@ -64,7 +70,7 @@
       "path": "pages/connect/index",
       "type": "page",
       "style": {
-        "navigationBarTitleText": "配网向导"
+        "navigationBarTitleText": "配网设置"
       }
     },
     {
@@ -79,14 +85,22 @@
       "type": "page",
       "layout": "default",
       "style": {
-        "navigationBarTitleText": "我的"
+        "navigationBarTitleText": "我的",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/personal/setting",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "设置"
       }
     },
     {
       "path": "pages/print/index",
       "type": "page",
       "style": {
-        "navigationBarTitleText": "远程打印"
+        "navigationBarTitleText": "上传文件"
       }
     },
     {
@@ -114,14 +128,7 @@
       "path": "pages/printer/index",
       "type": "page",
       "style": {
-        "navigationBarTitleText": "打印机列表"
-      }
-    },
-    {
-      "path": "pages/test/index",
-      "type": "page",
-      "style": {
-        "navigationBarTitleText": "测试页"
+        "navigationBarTitleText": "已关联打印机列表"
       }
     },
     {
@@ -131,14 +138,6 @@
       "style": {
         "navigationBarTitleText": "上传文件"
       }
-    },
-    {
-      "path": "pages/webview/sse",
-      "type": "page",
-      "layout": "default",
-      "style": {
-        "navigationBarTitleText": "查看打印任务"
-      }
     }
   ],
   "subPackages": []

+ 135 - 157
src/pages/assistant/index.vue

@@ -8,45 +8,63 @@
 </route>
 <template>
   <view class="page-list">
-    <wd-sticky>
-      <view class="sticky-box">
-        <wd-search
-          placeholder="请输入打印助手名称"
-          placeholder-left
-          hide-cancel
-          v-model="queryParams.asname"
-          @change="onSearch"
-          @clear="onSearch"
-        >
-          <!-- <template v-slot:prefix>
-            <wd-drop-menu custom-class="search-menu">
-              <wd-drop-menu-item v-model="queryParams.addType" :options="typeList" @change="onSearch" />
-            </wd-drop-menu>
-          </template> -->
-        </wd-search>
+    <!-- 添加猫耳助手 -->
+    <view class="add-contain" @click="toDetail('add')">
+      <view class="main-text">
+        <view class="tips">添加猫耳打印助手</view>
+        <view class="count">{{ `${total}台打印助手` }}</view>
       </view>
-    </wd-sticky>
+      <view class="icon"><view class="plus">+</view></view>
+    </view>
 
     <view class="list-contain">
       <template v-if="dataList.length > 0 || loadStatus == 'loading'">
-        <view v-for="item of dataList" :key="item.id" class="list-box" @click="toDetail('view', item.id)">
-          <view class="name">
-            <view class="main-text">
-              <view class="inline-text">{{ item.asname }}</view>
-              <wd-tag :type="item.onlineStatus == 'online' ? 'success' : 'danger'" mark custom-class="ml-2">
-                {{ getLabel(item.onlineStatus || 'offline', onlineStatus) }}
-              </wd-tag>
-              <wd-tag v-if="item.isIntranet" type="primary" mark custom-class="ml-2">局域网</wd-tag>
+        <view v-for="item of dataList"
+              :key="item.id"
+              class="item-box"
+              :class="{'active': item.onlineStatus == 'online'}"
+              @click="toDetail('view', item.id)">
+          <view class="info-box">
+            <view class="icon">
+              <i class="iconfont icon-combined"></i>
             </view>
-            <view class="sub-text">
-              {{ `添加方式: ${getLabel(item.addType, typeList)}` }}
+            <view class="info">
+              <view class="main-text">
+                <view class="name">{{ item.asname }}</view>
+                <view v-if="item.isIntranet" class="tag">局域网</view>
+                <view class="tag" :class="item.onlineStatus == 'online' ? 'success' : 'gray'" >
+                  {{ getLabel(item.onlineStatus || 'offline', onlineStatus) }}
+                </view>
+              </view>
+              <view class="sub-text">
+                {{ `IP: ${item.intranetIp}` }}
+              </view>
+              <view class="desc-text">
+                {{ item.createTime }}
+              </view>
             </view>
           </view>
-          <view class="opt" @click.stop="showShare(item)">
-            <wd-button type="icon" icon="share" open-type="share"></wd-button>
-          </view>
-          <view class="opt" @click.stop="showActions(item)">
-            <wd-button type="icon" icon="more"></wd-button>
+          <view class="opt-box">
+            <view class="opt-btn color-danger" @click.stop="handleDelete(item)">
+              <view class="inline-block">移除</view>
+            </view>
+            <view class="opt-btn" @click.stop="toDetail('edit', item.id)">
+              <view class="inline-block">编辑</view>
+            </view>
+            <button open-type="share" class="custom-share-btn" @click.stop="showShare(item)">
+              <view class="opt-btn">
+                <i class="iconfont icon-a-fenxiang2"></i>
+                <view class="inline-block">分享</view>
+              </view>
+            </button>
+            <view class="opt-btn" @click.stop="toConnect(item)">
+              <i class="iconfont icon-cloud"></i>
+              <view class="inline-block">联网设置</view>
+            </view>
+            <view class="opt-btn" @click.stop="toPrinter(item)">
+              <i class="iconfont icon-a-printer"></i>
+              <view class="inline-block">已关联打印机</view>
+            </view>
           </view>
         </view>
         <!-- 加载更多 -->
@@ -54,30 +72,17 @@
       </template>
       <wd-status-tip v-else image="content" tip="暂无内容" />
     </view>
-
-    <!-- 悬浮按钮 -->
-    <wd-fab
-      :expandable="false"
-      @click="toDetail('add')"
-    ></wd-fab>
-
-    <!-- 动作面板 -->
-    <wd-action-sheet
-      v-model="isShowActions"
-      :actions="currentActions"
-      :title="actionsTitle"
-      @close="isShowActions = false"
-      @select="selectActions"
-    />
   </view>
 </template>
 
 <script lang="ts" setup>
+import { useUserStore } from '@/store'
 import { useMessage, useToast } from 'wot-design-uni'
 import { getUserHubPage, deleteUserHub, testByIP } from '@/service/api'
-import { getLabel } from '@/utils'
+import { getLabel, toLogin } from '@/utils'
 import { debounce } from 'wot-design-uni/components/common/util'
 
+const isLogined = computed(() => !!useUserStore().token)
 const deviceImgSrc = ref('/static/images/device.png')
 const message = useMessage()
 const toast = useToast()
@@ -98,27 +103,12 @@ const dataList = ref([])
 const currentData: any = ref({})
 // 加载中: loading; 没有数据: finished; 错误: error;
 const loadStatus: any = ref('loading')
-// 动作面板
-const isShowActions = ref(false)
-const actionsTitle = ref('')
-const currentActions: any = ref([{ loading: true }])
 const isToTop = ref(false)
 
 defineOptions({
   name: 'UserHub',
 })
 
-// 根据状态 构造操作面板
-function buildCurrentActions() {
-  currentActions.value = [
-    { name: '查看' },
-    { name: '编辑' },
-    { name: '查看打印机' },
-    // { name: '分享打印助手' },
-    { name: '删除', color: '#fa4350' }
-  ]
-}
-
 function getDataList() {
   loadStatus.value = 'loading'
   const params = { ...queryParams }
@@ -131,7 +121,7 @@ function getDataList() {
   getUserHubPage(params)
     .then((res: any) => {
       if (res.code === 0 && res.body) {
-        total.value = res.body.total
+        total.value = res.body.total || 0
         if (queryParams.pageNo === 1) {
           dataList.value = res.body.records || []
         } else {
@@ -171,19 +161,24 @@ const onSearch = debounce(() => {
 
 // 跳转到详情(新增add / 编辑edit / 查看view)
 function toDetail(type: string, id?: string) {
-  uni.navigateTo({
-    url: `/pages/assistant/detail?type=${type}&id=${id || ''}`,
-  })
+  if (isLogined.value) {
+    uni.navigateTo({
+      url: `/pages/assistant/detail?type=${type}&id=${id || ''}`,
+    })
+  } else {
+    toast.warning('请先前往登录')
+    toLogin(1500)
+  }
 }
 
-function handleDelete() {
+function handleDelete(data) {
   message
     .confirm({
       title: '提示',
-      msg: `是否删除打印助手: ${currentData.value.asname} ?`,
+      msg: `是否删除打印助手: ${data.asname} ?`,
     })
     .then(() => {
-      deleteUserHub(currentData.value.id)
+      deleteUserHub(data.id)
         .then((res: any) => {
           if (res.code === 0) {
             toast.success('删除成功')
@@ -201,9 +196,9 @@ function handleDelete() {
 }
 
 // 跳转到打印机列表
-function toPrinter() {
+function toPrinter(data) {
   uni.navigateTo({
-    url: `/pages/printer/index?id=${currentData.value.id || ''}&asname=${currentData.value.asname}&ip=${currentData.value.isIntranet && currentData.value.ipList[0]}`,
+    url: `/pages/printer/index?id=${data.id || ''}&asname=${data.asname}&ip=${data.isIntranet && data.ipList[0]}`,
   })
 }
 
@@ -211,30 +206,10 @@ function showShare(data: any) {
   currentData.value = data || {}
 }
 
-function showActions(data: any) {
-  actionsTitle.value = data.asname ? `打印助手: ${data.asname}` : '操作'
-  currentData.value = data || {}
-  buildCurrentActions()
-  isShowActions.value = true
-}
-
-function selectActions(data: any) {
-  switch (data.item.name) {
-    case '查看':
-      toDetail('view', currentData.value.id)
-      break
-    case '编辑':
-      toDetail('edit', currentData.value.id)
-      break
-    case '查看打印机':
-      toPrinter()
-      break;
-    case '分享打印助手':
-      break;
-    case '删除':
-      handleDelete()
-      break
-  }
+function toConnect() {
+  uni.navigateTo({
+    url: `/pages/connect/index`,
+  })
 }
 
 // 查询列表, 滚动到顶部, 返回第一页
@@ -248,7 +223,12 @@ function resetDataList() {
 
 // 页面加载
 onLoad(() => {
-  getDataList()
+  if (isLogined.value) {
+    getDataList()
+  } else {
+    toast.warning('请先前往登录')
+    toLogin(1500)
+  }
   // 监听刷新
   uni.$on('refreshData', () => {
     resetDataList()
@@ -288,77 +268,75 @@ onShareAppMessage(() => {
 </script>
 
 <style lang="scss" scoped>
-.sticky-box {
-  width: 100vw;
-  height: 100rpx;
-  background-color: #ffffff;
-}
-.search-type {
-  position: relative;
-  height: 60rpx;
-  padding: 0 16rpx 0 32rpx;
-  line-height: 60rpx;
-}
-.search-type::after {
-  position: absolute;
-  top: 10rpx;
-  right: 0;
-  bottom: 10rpx;
-  width: 2rpx;
-  content: '';
-  background: rgba(0, 0, 0, 0.25);
-}
-.search-type {
-  :deep(.icon-arrow) {
-    display: inline-block;
-    font-size: 40rpx;
-    vertical-align: middle;
-  }
-}
-.list-contain {
-  padding: 10rpx 30rpx 30rpx;
+.page-list {
+  min-height: calc(100vh - 40rpx);
+  padding: 20rpx;
   overflow-y: auto;
+}
 
-  .list-box {
+.add-contain {
+  display: flex;
+  align-items: center;
+  padding: 40rpx;
+  background: linear-gradient(180deg, rgba(15, 95, 254, 1) 0%, rgba(72, 151, 253, 0.95) 100%);
+  border-radius: 40rpx;
+  .main-text {
+    flex: 1;
+    color: #fff;
+    .tips {
+      font-size: 36rpx;
+    }
+    .count {
+      display: inline-block;
+      padding: 10rpx 30rpx;
+      margin-top: 20rpx;
+      background-color: rgb(255, 255, 255, 0.2);
+      border-radius: 30rpx;
+      font-size: 28rpx;
+    }
+  }
+  .icon {
+    width: 80rpx;
+    height: 80rpx;
+    border-radius: 40rpx;
+    background-color: #fff;
+    color: var(--wot-color-theme);
     display: flex;
     align-items: center;
-    padding: 30rpx 0 30rpx 30rpx;
-    margin-bottom: 30rpx;
-    border: 1px solid #eee;
-
-    .name {
-      flex: 1;
-      .main-text {
-        word-break: break-all;
-        vertical-align: middle;
+    justify-content: center;
+    .plus {
+      font-size: 48rpx;
+    }
+  }
+}
 
-        .inline-text {
-          display: inline;
-          vertical-align: middle;
-          word-break: break-all;
+// 使用公共列表卡片样式
+.list-contain {
+  margin-top: 40rpx;
+  .item-box {
+    .info-box {
+      .icon {
+        width: 140rpx;
+        .iconfont {
+          font-size: 100rpx;
         }
       }
-      .sub-text {
-        margin-top: 20rpx;
-        font-size: 28rpx;
-        color: #00000073;
-      }
-    }
-    .opt {
-      width: 80rpx;
-      text-align: center;
     }
   }
 }
-//搜索下拉菜单
-:deep(.search-menu .wd-drop-menu__list) {
+
+/* 隐藏原生按钮样式 */
+.custom-share-btn {
+  display: inline-block;
+  padding: 0;
+  margin: 0;
   background: none;
+  border: none;
+  line-height: 1;
+  border-radius: 0;
 }
-:deep(.search-menu .wd-drop-menu__item) {
-  height: 62rpx;
-  line-height: 62rpx;
-}
-:deep(.search-menu .wd-drop-menu__item-title::after) {
-  content: none;
+
+.custom-share-btn::after {
+  border: none;
 }
 </style>

+ 112 - 12
src/pages/connect/index.vue

@@ -2,14 +2,94 @@
 <route lang="json5" type="page">
 {
   style: {
-    navigationBarTitleText: '配网向导',
+    navigationBarTitleText: '配网设置',
   },
 }
 </route>
 
 <template>
   <view class="page-form">
-    <view class="form-title">
+    <view class="video-contain">
+      <view class="title">
+        <i class="iconfont icon-cloud"></i>
+        <text>配网快速教程</text>
+      </view>
+      <view class="video">视频区</view>
+    </view>
+
+    <view class="guide-contain">
+      <view class="">配网步骤</view>
+      <view class="step-contain">
+        <view class="step-item">
+          <view class="tag">step1</view>
+          <view class="icon">
+            <i class="iconfont icon-shangchuanwenjian"></i>
+          </view>
+          <view class="label">先连接"maoer-hub"开头的WIFI</view>
+        </view>
+        <view class="step-link">···</view>
+        <view class="step-item">
+          <view class="tag">step2</view>
+          <view class="icon">
+            <i class="iconfont icon-dayinshezhi"></i>
+          </view>
+          <view class="label">开始配网</view>
+        </view>
+        <view class="step-link">···</view>
+        <view class="step-item">
+          <view class="tag">step3</view>
+          <view class="icon">
+            <i class="iconfont icon-dayinwancheng"></i>
+          </view>
+          <view class="label">选择链接WIFI</view>
+        </view>
+      </view>
+    </view>
+
+    <view class="opt-contain">
+      <view class="btn" @click="getConnectedWifi()">开始配网</view>
+      <i class="iconfont icon-xiayibu icon-down"></i>
+      <view class="tips">配网成功后再选择WIFI</view>
+    </view>
+
+    <view class="form-contain">
+      <wd-form ref="form" :model="formData">
+        <wd-cell-group custom-class="form-group" border>
+          <wd-select-picker
+            v-model="formData.ssid"
+            label="无线名称"
+            label-width="100px"
+            prop="ssid"
+            type="radio"
+            filterable
+            placeholder="请选择家里的无线名称"
+            :columns="wifiList"
+            value-key="ssid"
+            label-key="ssid"
+            :loading="loading"
+            :max="1"
+            :show-confirm="false"
+            :rules="[{ required: true, message: '请选择家里的无线名称' }]"
+          />
+          <wd-input
+            v-model="formData.pwd"
+            label="无线密码"
+            label-width="100px"
+            prop="pwd"
+            placeholder="请输入家里的无线密码"
+            clearable
+            show-password
+            :rules="[{ required: true, pattern: /^.{8,}$/, message: '请输入不少于8位无线密码' }]"
+          />
+        </wd-cell-group>
+
+        <view class="form-footer">
+          <wd-button type="primary" size="large" :disabled="loading" @click="handleSubmit()" block>提交</wd-button>
+        </view>
+      </wd-form>
+    </view>
+
+    <!-- <view class="form-title">
       <view>配网步骤</view>
     </view>
     <view class="tips-box">
@@ -62,7 +142,7 @@
       <view class="form-footer">
         <wd-button type="primary" size="large" :disabled="loading" @click="handleSubmit()" block>提交</wd-button>
       </view>
-    </wd-form>
+    </wd-form> -->
   </view>
 </template>
 
@@ -192,18 +272,38 @@ onLoad(() => {
 </script>
 
 <style lang="scss" scoped>
-.tips-box {
-  width: calc(100% - 60rpx);
-  padding: 40rpx 30rpx;
-  text-align: center;
+.page-form {
   background-color: #fff;
-  border-radius: 16rpx;
 }
-.check-box {
-  margin: 40rpx 0;
-  .check-result {
-    margin-bottom: 30rpx;
+.guide-contain {
+  margin-top: 20rpx;
+}
+.opt-contain {
+  color: #666;
+  .btn {
+    margin-top: 20rpx;
+  }
+  .icon-down {
+    font-size: 50rpx;
+    color: #808080;
+    margin-top: 20rpx;
+  }
+  .tips {
+    margin-top: 20rpx;
   }
 }
+// .tips-box {
+//   width: calc(100% - 60rpx);
+//   padding: 40rpx 30rpx;
+//   text-align: center;
+//   background-color: #fff;
+//   border-radius: 16rpx;
+// }
+// .check-box {
+//   margin: 40rpx 0;
+//   .check-result {
+//     margin-bottom: 30rpx;
+//   }
+// }
 </style>
 

+ 191 - 129
src/pages/index/index.vue

@@ -10,104 +10,100 @@
 <template>
   <view class="my-page">
     <!-- 自定义导航栏 -->
-    <pyh-nv ref="nvRef" :config="nvConfig">
-      <wd-img :src="logoSrc" height="30" mode="heightFix"></wd-img>
-    </pyh-nv>
+    <pyh-nv ref="nvRef" :config="nvConfig"></pyh-nv>
 
-    <view class="px-4">
-      <!-- 主图轮播 1:1 height="calc(100vw - 60rpx)" -->
+    <view class="page-contain">
       <wd-swiper
         v-model:current="current"
         :list="swiperList"
         :indicator="{ type: 'dots-bar' }"
         value-key="url"
-        height="calc(66.6vw - 20rpx)"
+        height="400rpx"
         imageMode="widthFix"
         :duration="500"
-        custom-class="my-swiper shadow-class"
+        custom-class="my-swiper"
       ></wd-swiper>
-      <!-- 功能区 -->
-      <view class="guide-box shadow-class">
-        <view class="guide-item" @click="toUserHub('')">
-          <wd-img :src="deviceImgSrc" width="90" mode="widthFix"></wd-img>
-          <view class="item-title">打印助手</view>
-          <view class="item-desc">我的打印助手</view>
+
+      <!-- 主入口 -->
+      <view class="guide-box">
+        <view class="guide-item bg-orange" @click="openWebView()">
+          <view class="item-title">文档打印</view>
+          <view class="item-desc">支持PDF、Word、PPT、Excel</view>
+          <view class="item-btn">去打印</view>
         </view>
-        <view class="guide-item" @click="openWebView()">
-          <wd-img :src="fileImgSrc" width="90" mode="widthFix"></wd-img>
-          <view class="item-title">手机文件</view>
-          <view class="item-desc">无需驱动 隔空打印</view>
+
+        <view class="guide-item bg-blue-light" @click="toPrint('image')">
+          <view class="item-title">照片打印</view>
+          <view class="item-desc">支持jpg、png、gif、webp</view>
+          <view class="item-btn">去打印</view>
         </view>
       </view>
-      <!-- 补充入口 -->
+      
+      <!-- 次入口 -->
       <view class="content">
-        <view class="section">
-          <view class="item">
-            <view class="title" @click="toPrint('wxImg')">
-              <wd-img :src="wechatImageSrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">微信图片</view>
-            </view>
+        <view class="item wx-file" @click="toPrint('wxFile')">
+          <view class="item-text">
+            <view class="title-text">微信文件打印</view>
+            <view class="desc-text">聊天文件、云文档等打印</view>
           </view>
-          <!-- msg -->
-          <view class="item" @click="toPrint('image')">
-            <view class="title">
-              <wd-img :src="pictureSrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">相册图片</view>
-            </view>
+          <view class="item-icon">
+            <wd-img :src="documentSrc" width="48" mode="widthFix"></wd-img>
           </view>
-          <view class="item">
-            <view class="title" @click="toPrint('wxFile')">
-              <wd-img :src="wechatFileSrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">微信文件</view>
-            </view>
+        </view>
+
+        <view class="item wx-invoice" @click="toPrint('invoice')">
+          <view class="item-text">
+            <view class="title-text">发票打印</view>
+            <view class="desc-text">快速选择发票打印</view>
           </view>
-          <view class="item">
-            <view class="title" @click="toPrint('invoice')">
-              <wd-img :src="wechatInvoiceSrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">微信发票</view>
-            </view>
+          <view class="item-icon">
+            <wd-img :src="invoiceSrc" width="48" mode="widthFix"></wd-img>
           </view>
-          <view class="item" @click="toConnect()">
-            <view class="title">
-              <wd-img :src="connectSrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">设备配网</view>
-            </view>
+        </view>
+
+        <view class="item wx-image" @click="toPrint('wxImg')">
+          <view class="item-text">
+            <view class="title-text">微信图片打印</view>
+            <view class="desc-text">聊天图片、云图片等打印</view>
           </view>
-          <view class="item" @click="toJob()">
-            <view class="title">
-              <wd-img :src="historySrc" width="40" mode="widthFix"></wd-img>
-              <view class="title-text">打印任务</view>
-            </view>
+          <view class="item-icon">
+            <wd-img :src="pictureSrc" width="48" mode="widthFix"></wd-img>
           </view>
-          <!-- <view class="item">
-            <view class="title">
-              <image :src="settingSrc"></image>
-              <view class="title-text">预留入口</view>
-            </view>
-            <view class="tips">描述信息</view>
-          </view> -->
         </view>
+
+        <!-- 临时入口 -->
+        <!-- <view @click="toUserHub()">打印助手</view>
+        <view @click="toConnect()">设备配网</view>
+        <view @click="toJob()">打印任务</view> -->
       </view>
     </view>
+
+    <!-- TODO: showGuide 增加自定义confirm, 引导添加设备 -->
   </view>
 </template>
 
 <script lang="ts" setup>
 import { useUserStore } from '@/store'
-import { useToast } from 'wot-design-uni'
+import { useToast, useMessage } from 'wot-design-uni'
 import { toLogin } from '@/utils'
+import { getUserHubPage } from '@/service/api'
 
 defineOptions({
   name: 'Home',
 })
 
-const deviceInfo = uni.getDeviceInfo()  // 更多系统信息用 getSystemInfoSync
 const toast = useToast()
+const message = useMessage()
+const deviceInfo = uni.getDeviceInfo()  // 更多系统信息用 getSystemInfoSync
 const isLogined = computed(() => !!useUserStore().token)
 const nvRef: any = ref()
 const nvConfig = ref({
   title: '首页',
-  type: 'slot', // default slot logo
+  type: 'logo', // default slot logo
+  logo: {
+    src: '/static/images/logo_top.png',
+    style: 'height: 60rpx'
+  },
   back: {
     hide: true,
   },
@@ -118,29 +114,12 @@ const nvConfig = ref({
     initColor: '#000000',
   },
 })
+const showGuide = ref(false)
 const swiperList = ref([])
 const current = ref(0)
-
-const logoSrc = ref('/static/images/logo_temp1.png')
-// const deviceImgSrc = ref('/static/images/device.png')
-// const fileImgSrc = ref('/static/images/file.png')
-// const connectSrc = ref('/static/images/connect.png')
-// const pictureSrc = ref('/static/images/picture.png')
-// const wechatImageSrc = ref('/static/images/wechat_file.png')
-// const wechatFileSrc = ref('/static/images/wechatFile.png')
-// const wechatInvoiceSrc = ref('/static/images/wechat_invoice.png')
-// const historySrc = ref('/static/images/history.png')
-// const shareSrc = ref('/static/images/share.png')
-
-const deviceImgSrc = ref('/static/images/icon/printer-two.png')
-const fileImgSrc = ref('/static/images/icon/folder-open.png')
-const connectSrc = ref('/static/images/icon/connect.png')
-const pictureSrc = ref('/static/images/icon/album.png')
-const wechatImageSrc = ref('/static/images/icon/picture.png')
-const wechatFileSrc = ref('/static/images/icon/file.png')
-const wechatInvoiceSrc = ref('/static/images/icon/cards.png')
-const historySrc = ref('/static/images/icon/history-query.png')
-const shareSrc = ref('/static/images/icon/wechat.png')
+const documentSrc = ref('/static/images/document.png')
+const invoiceSrc = ref('/static/images/invoice.png')
+const pictureSrc = ref('/static/images/picture.png')
 
 // 初始化 swiperList 数组
 function initSwiperList() {
@@ -208,8 +187,42 @@ function toJob() {
   }
 }
 
+function checkHub() {
+  let params = {
+    pageNo: 1,
+    pageSize: 10,
+  }
+  getUserHubPage(params).then((res :any) => {
+    if (res.code == 0 && res.body && res.body.total == 0) {
+      showGuide.value = true
+      // TODO: 需修改为自定义的全局弹窗
+      message.confirm({
+        msg: "您还没添加猫耳打印助手,现在就去添加吗?",
+        closeOnClickModal: false,
+        confirmButtonText: "立即添加",
+        cancelButtonText: "不感兴趣",
+      }).then(() => {
+        toAddUserHub()
+      }).catch(() => {})
+    }
+  }).catch(() => {})
+}
+
+function toAddUserHub() {
+  if (isLogined.value) {
+    uni.navigateTo({
+      url: `/pages/assistant/detail?type=add`,
+    })
+  } else {
+    toast.warning('请先前往登录')
+    toLogin(1500)
+  }
+}
+
 onLoad((option: any) => {
   initSwiperList()
+  // 检查是否已添加助手, 没有则弹窗提示
+  if (isLogined.value) checkHub()
 })
 
 // 监听滚动
@@ -220,7 +233,6 @@ onPageScroll((e) => {
 
 <style lang="scss" scoped>
 .my-page {
-  background-color: #eeeeee;
   background-size: 100% auto;
   background-position: top;
   background-repeat: no-repeat;
@@ -230,79 +242,129 @@ onPageScroll((e) => {
   overflow-y: auto;
 }
 
+.page-contain {
+  padding: 0 20rpx;
+}
+
 :deep(.my-swiper) {
-  border-radius: 40rpx !important;
+  border-radius: 20rpx !important;
   swiper {
-    border-radius: 40rpx !important;
+    border-radius: 20rpx !important;
   }
 }
 
 .guide-box {
   display: flex;
-  padding: 20rpx 0 20rpx;
-  margin-top: 30rpx;
-  border-radius: 40rpx;
-  background-color: #fff;
+  margin-top: 20rpx;
+
   .guide-item {
     flex: 1;
-    text-align: center;
+    color: #ffffff;
+    border-radius: 40rpx;
+    padding: 50rpx 20rpx;
+    position: relative;
+    min-height: 300rpx;
+
     .item-title {
-      font-size: 32rpx;
-      font-weight: bold;
-      margin-top: 4rpx;
+      font-size: 48rpx;
     }
     .item-desc {
       font-size: 24rpx;
-      margin-top: 4rpx;
-      margin-bottom: 20rpx;
+      margin-top: 24rpx;
+    }
+    .item-btn {
+      position: absolute;
+      min-width: 100rpx;
+      padding: 10rpx 40rpx;
+      right: 30rpx;
+      bottom: 50rpx;
+      text-align: center;
+      font-size: 36rpx;
+      color: #6E0000;
+      background-color: #FDDD62;
+      border: 4rpx solid #FFF3CD;
+      border-radius: 32rpx;
     }
   }
   .guide-item + .guide-item {
-    border-left: 1px solid transparent; /* 设置透明边框以便于渐变可见 */
-    border-image: linear-gradient(to bottom, white, #b8b8b8, white) 10 10; /* 使用渐变作为边框图片 */
+    margin-left: 20rpx;
+  }
+  .bg-orange {
+    background-color: #FF894F;
+    border: 10rpx solid #FFE7DC;
+  }
+  .bg-blue-light {
+    background-color: #58BEFF;
+    border: 10rpx solid #DEF2FF;
+  }
+  .bg-blue {
+    background-color: var(--wot-color-theme);
   }
 }
 
 .content {
-  width: 100%;
-  position: relative;
-  margin-top: 30rpx;
-
-  .section {
+  .item {
     display: flex;
-    flex-wrap: wrap;
-    justify-content: center;
     align-items: center;
-    margin-left: -20rpx;
+    margin-top: 20rpx;
+    padding: 30rpx;
+    border-radius: 20rpx;
     
-    .item {
-      flex: 1 1 calc(50% - 20px);
-      // background-color: #e1e1e1;
-      background-color: #ffffff;
-      padding: $uni-spacing-row-lg 0;
-      margin: 0 0 20rpx 20rpx;
+    .item-text {
+      flex: 1;
+      .title-text {
+        font-size: 36rpx;;
+      }
+      .desc-text {
+        font-size: 24rpx;
+        margin-top: 16rpx;
+      }
+    }
+    .item-icon {
+      width: 160rpx;
+      height: 160rpx;
+      line-height: 160rpx;
+      text-align: center;
+      border-radius: 50%;
       display: flex;
-      flex-direction: column;
       align-items: center;
       justify-content: center;
-      border-radius: 30rpx;
-      
-      .title {
-        width: 100%;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: $uni-font-size-lg;
-        
-        .title-text {
-          margin-left: 20rpx;
-        }
-      }
-      
-      .tips {
-        color: $uni-text-color-grey;
-        font-size: $uni-font-size-base;
-      }
+    }
+  }
+  .wx-file {
+    background-color: rgba(226, 233, 251, 0.5);
+    .title-text {
+      color: #0F62FE;
+    }
+    .desc-text {
+      color: rgba(15, 98, 254, 0.6);
+    }
+    .item-icon {
+      background-color: rgba(86, 142, 254, 0.2);
+    }
+  }
+  .wx-invoice {
+    background-color: rgba(225, 242, 230, 0.8);
+    .title-text {
+      color: #66CC00;
+    }
+    .desc-text {
+      color: rgba(102, 204, 0, 0.6);
+    }
+    .item-icon {
+      background-color: rgba(186, 232, 119, 0.3);
+    }
+  }
+  .wx-image {
+    background-color: rgba(248, 244, 233, 0.5);
+    .title-text {
+      color: #FC7234;
+    }
+    .desc-text {
+      color: rgba(252, 114, 52, 0.6);
+    }
+    .item-icon {
+      background-color: rgba(255, 153, 0, 0.2);
     }
   }
 }

+ 112 - 88
src/pages/personal/index.vue

@@ -3,52 +3,60 @@
   layout: 'default',
   style: {
     navigationBarTitleText: '我的',
+    navigationStyle: 'custom'
   },
 }
 </route>
 
 <template>
-  <view class="main overflow-hidden pt-2 px4" :style="{ marginTop: safeAreaInsets?.top + 'px' }">
+  <view class="personal-page">
     <view class="head">
       <wd-img
-        v-if="userInfo.avatar"
-        custom-class="img-btn"
-        :width="40"
-        :height="40"
         :src="userInfo.avatar"
+        :width="60"
+        :height="60"
+        mode="aspectFit"
+        custom-class="img-btn"
       />
-      <view class="head-name">{{ isLogined ? userInfo.name : "请登录" }}</view>
-    </view>
-    <view class="main-content mt6">
-      <!-- <view class="content-item line-b" @click="toTest">
-        <view>测试页</view>
-        <wd-icon name="arrow-right" size="20px" color="#808080"></wd-icon>
-      </view> -->
-      <view class="content-item line-b" @click="toAddUserHub">
-        <view>添加打印助手</view>
-        <wd-icon name="arrow-right" size="20px" color="#808080"></wd-icon>
+      <view class="main-text">
+        <view v-if="isLogined">
+          <view class="tips">{{ userInfo.name }}</view>
+          <view class="count">{{ `猫耳打印陪伴您1年了` }}</view>
+        </view>
+        <view v-else class="tips" @click="toLogin()">
+          请点击登录
+        </view>
       </view>
-      <view class="content-item line-b" @click="toJob">
-        <view>查看打印任务</view>
-        <wd-icon name="arrow-right" size="20px" color="#808080"></wd-icon>
+      <view v-if="isLogined" class="icon" @click="toSetting()">
+        <i class="iconfont icon-shezhi"></i>
       </view>
-      <view v-if="isLogined" class="content-item" @click="handleLogout">
-        <view>退出登录</view>
-        <wd-icon name="arrow-right" size="20px" color="#808080"></wd-icon>
+    </view>
+
+    <view class="menu-contain">
+      <view class="item-box" @click="toAddUserHub">
+        <view class="icon">
+          <i class="iconfont icon-shebei1"></i>
+        </view>
+        <view class="main-text">添加打印助手</view>
+        <view class="plus-btn">
+          <view class="plus">+</view>
+        </view>
       </view>
-      <view v-else class="content-item" @click="toLogin()">
-        <view>前往登录</view>
-        <wd-icon name="arrow-right" size="20px" color="#808080"></wd-icon>
+      <view class="item-box" @click="toJob">
+        <view class="icon">
+          <i class="iconfont icon-renwu"></i>
+        </view>
+        <view class="main-text">查看打印任务</view>
+        <wd-icon name="arrow-right" size="14px" color="#999999"></wd-icon>
       </view>
     </view>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { logout } from '@/service/api/index'
 import { useUserStore } from '@/store'
 import { useToast } from 'wot-design-uni'
-import { toLogin, toLoginWait } from '@/utils'
+import { toLogin } from '@/utils'
 
 // 获取屏幕边界到安全区域距离
 const { safeAreaInsets } = uni.getSystemInfoSync()
@@ -59,6 +67,12 @@ const userInfo = reactive({
 const toast = useToast()
 const isLogined = computed(() => !!useUserStore().token)
 
+function toSetting() {
+  uni.navigateTo({
+    url: `/pages/personal/setting`,
+  })
+}
+
 function toAddUserHub() {
   if (isLogined.value) {
     uni.navigateTo({
@@ -81,88 +95,98 @@ function toJob() {
   }
 }
 
-function handleLogout() {
-  useUserStore().clearUserInfo()
-  toast.success('退出登录成功')
-  toLoginWait(1500)
-}
-
 function initFn() {
   userInfo.name = useUserStore().userInfo?.name || "微信用户"
   userInfo.avatar = "/static/images/avatar.png"
   // userInfo.avatar = useUserStore().userInfo.avatar
 }
 
-function toTest() {
-  if (isLogined.value) {
-    uni.navigateTo({
-      url: `/pages/test/index`,
-    })
-  } else {
-    toast.warning('请先前往登录')
-    toLogin(1500)
-  }
-}
-
 onLoad(() => {
   initFn()
 })
 </script>
 
 <style lang="scss" scoped>
+.personal-page {
+  background-size: 100% auto;
+  background-position: top;
+  background-repeat: no-repeat;
+  width: 100%;
+  min-height: 100vh;
+  padding: 0;
+  overflow-y: auto;
+  background-color: #F5F5F5;
+}
 .head {
+  min-height: 400rpx;
   display: flex;
   align-items: center;
-  .head-name {
-    @apply pl-3;
+  background: linear-gradient(180deg, rgba(15, 95, 254, 1) 0%, rgba(72, 151, 253, 0.95) 100%);
+  color: #fff;
+  padding: 60rpx 30rpx;
+  .main-text {
+    margin-left: 40rpx;
+    flex: 1;
+    .tips {
+      font-size: 36rpx;
+    }
+    .count {
+      display: inline-block;
+      padding: 10rpx 30rpx;
+      margin-top: 20rpx;
+      background-color: rgb(255, 255, 255, 0.2);
+      border-radius: 30rpx;
+      font-size: 28rpx;
+    }
+  }
+  .icon {
+    .iconfont {
+      color: #fff;
+      font-size: 60rpx;
+    }
   }
-}
-.main-content {
-  padding: 20rpx;
-  background-color: white;
-  border-radius: 16rpx;
-}
-.content-item {
-  display: flex;
-  align-items: start;
-  justify-content: space-between;
-  padding: 30rpx 0;
-}
-.line-b {
-  border-bottom: 1px solid #eee;
-}
-:deep(.head .wd-upload__evoke) {
-  width: 80rpx;
-  height: 80rpx;
-  margin-bottom: 0;
-  border-radius: 100%;
-}
-:deep(.wd-upload) {
-  display: flex;
-}
-:deep(.wd-upload__evoke-num) {
-  display: none;
-}
-:deep(.wd-icon) {
-  font-size: 50rpx;
 }
 :deep(.img-btn .wd-img__image) {
-  width: 80rpx;
-  height: 80rpx;
-  border-radius: 40rpx;
-}
-:deep(.wd-upload__preview) {
-  display: none !important;
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 60rpx;
 }
-:deep(.gray-btn.wd-button) {
-  width: 80rpx;
-  height: 80rpx;
-  background-color: #ddd;
+.menu-contain {
+  background-color: rgba(255, 255, 255, 0.8);
   border-radius: 40rpx;
-}
-:deep(.form-ipt) {
-  padding-right: 0 !important;
-  padding-left: 0 !important;
+  margin: -120rpx 20rpx 0;
+  min-height: calc(100vh - 440rpx);
+  .item-box {
+    display: flex;
+    align-items: center;
+    padding: 30rpx;
+    border-bottom: 2rpx solid #ddd;
+    .icon {
+      margin-right: 40rpx;
+      .iconfont {
+        color: var(--wot-color-theme);
+        font-size: 60rpx;
+      }
+    }
+    .main-text {
+      flex: 1;
+      font-size: 28rpx;
+      color: #000;
+    }
+    .plus-btn {
+      width: 60rpx;
+      height: 60rpx;
+      border-radius: 30rpx;
+      background-color: var(--wot-color-theme);
+      color: #fff;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      .plus {
+        font-size: 40rpx;
+      }
+    }
+  }
 }
 </style>
 

+ 52 - 0
src/pages/personal/setting.vue

@@ -0,0 +1,52 @@
+<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
+<route lang="json5">
+{
+  style: {
+    navigationBarTitleText: '设置',
+  },
+}
+</route>
+<template>
+  <view class="page-form">
+    <view class="full-btn">登录其他账号</view>
+    <view class="full-btn" @click="handleLogout">退出登录</view>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { useMessage, useToast } from 'wot-design-uni'
+import { useUserStore } from '@/store'
+import { toLoginWait } from '@/utils'
+
+const message = useMessage()
+const toast = useToast()
+
+defineOptions({
+  name: 'Setting',
+})
+
+function handleLogout() {
+  useUserStore().clearUserInfo()
+  toast.success('退出登录成功')
+  toLoginWait(1500)
+}
+
+onLoad((option) => {
+})
+</script>
+
+<style lang="scss" scoped>
+.page-form {
+  padding: 20rxp;
+}
+.full-btn {
+  width: 100%;
+  text-align: center;
+  font-size: 28rpx;
+  line-height: 40rpx;
+  padding: 30rpx 0;
+  margin-bottom: 20rpx;
+  background-color: #fff;
+  border-radius: 20rpx;
+}
+</style>

+ 250 - 175
src/pages/print/index.vue

@@ -2,152 +2,178 @@
 <route lang="json5">
 {
   style: {
-    navigationBarTitleText: '远程打印',
+    navigationBarTitleText: '上传文件',
   },
 }
 </route>
 
 <template>
   <view class="page-form">
-    <!-- 选择打印机--获取打印参数--上传打印 -->
-    <wd-form ref="form" :model="formData">
-      <wd-cell-group custom-class="form-group" border>
-        <wd-cell title="上传文件"
-                 title-width="100px"
-                 required
-                 prop="fileList"
-                 custom-class="my-cell">
-          <view class="file-list">
-            <view v-for="(item, index) of fileList"
-                  :key="item.filePath"
-                  class="file-item"
-                  @click="previewFile(item.name, item.filePath)">
-              <view class="item-icon">
-                <wd-img
-                  :src="getFileIcon(item.name)"
-                  :width="20"
-                  :height="20"
-                  mode="aspectFit"
-                ></wd-img>
-              </view>
-              <view class="item-name">{{ item.name }}</view>
-              <view class="item-del" @click.stop="removeFile(index)">
-                <wd-img
-                  :src="delSrc"
-                  :width="20"
-                  :height="20"
-                  mode="aspectFit"
-                ></wd-img>
-              </view>
-            </view>
-
-            <!-- 选择文件: 支持多选多个 (系统文件另外传入) -->
-            <wd-button v-if="accept != 'all'" size="small" @click="selectFile()">选择文件</wd-button>
+    <view v-if="fileList.length == 0" class="guide-contain">
+      <view>打印步骤</view>
+      <view class="step-contain">
+        <view class="step-item">
+          <view class="tag">step1</view>
+          <view class="icon">
+            <i class="iconfont icon-shangchuanwenjian"></i>
           </view>
-        </wd-cell>
-
-        <wd-select-picker
-          v-model="formData.printer"
-          label="打印机"
-          label-width="100px"
-          type="radio"
-          :columns="printerList"
-          value-key="id"
-          label-key="showName"
-          :max="1"
-          :show-confirm="false"
-          filterable
-          placeholder="请选择打印机"
-          prop="printer"
-          :rules="[{ required: true, message: '请选择打印机' }]"
-          @change="handlePrinterChange"
-        />
-        <!-- 动态属性 -->
-        <template v-for="option of printerOptions" :key="option.key">
-          <!-- type: select 下拉选项 -->
-          <wd-select-picker
-            v-if="option.type == 'select'"
-            v-model="formData[option.key]"
-            :label="option.text"
-            label-width="100px"
-            type="radio"
-            :columns="option.values"
-            value-key="key"
-            label-key="text"
-            :max="1"
-            :show-confirm="false"
-            filterable
-            :placeholder="`请选择${option.text}`"
-            :prop="option.key"
-            :rules="[{ required: true, message: `请选择${option.text}` }]"
-          />
-          <!-- type: radio 单选项 -->
-          <wd-cell v-if="option.type == 'radio'"
-                   :title="option.text"
-                   title-width="100px"
-                   custom-class="my-cell"
-                   :prop="option.key"
-                   :rules="[{ required: true, message: `请选择${option.text}` }]">
-            <wd-radio-group v-model="formData[option.key]"
-                            shape="dot"
-                            inline>
-              <wd-radio v-for="item of option.values"
-                        :key="item.key"
-                        :value="item.key">
-                {{ item.text }}
-              </wd-radio>
-            </wd-radio-group>
-          </wd-cell>
-          <!-- type: rang 范围值, 传参是拼接字符串'xxx_str,xxx_end', 默认全部all不用传 -->
-          <wd-cell v-if="option.type == 'rang'"
-                   :title="option.text"
-                   title-width="100px"
-                   custom-class="my-cell"
-                   :prop="option.key"
-                   required>
-            <!-- 1. 先radio选择 all / range, 默认all全部, 仅单个文件时支持range选项 -->
-            <wd-radio-group v-model="formData[option.key]"
-                            shape="dot"
-                            inline>
-              <wd-radio value="all">所有页</wd-radio>
-              <wd-radio v-if="fileList.length == 1 && !isImg()" value="range">输入范围</wd-radio>
-            </wd-radio-group>
-            <!-- 2. 当上传单个文件(非图片)且radio选择 range 时允许输入范围, 从 XXX 到 XXX) -->
-            <view v-if="!isImg() && formData[option.key] == 'range'" style="text-align: left; margin-top: 10px">
-              <view class="inline-txt" style="margin-left: 0">从</view>
-              <wd-input
-                custom-style="display: inline-block; width: 70px; vertical-align: middle"
-                placeholder="起始页"
-                v-model="formData[option.key + '_str']"
-              />
-              <view class="inline-txt">到</view>
-              <wd-input
-                custom-style="display: inline-block; width: 70px; vertical-align: middle"
-                placeholder="结束页"
-                v-model="formData[option.key + '_end']"
+          <view class="label">上传文件</view>
+        </view>
+        <view class="step-link">···</view>
+        <view class="step-item">
+          <view class="tag">step2</view>
+          <view class="icon">
+            <i class="iconfont icon-dayinshezhi"></i>
+          </view>
+          <view class="label">打印设置</view>
+        </view>
+        <view class="step-link">···</view>
+        <view class="step-item">
+          <view class="tag">step3</view>
+          <view class="icon">
+            <i class="iconfont icon-dayinwancheng"></i>
+          </view>
+          <view class="label">打印印刷</view>
+        </view>
+      </view>
+
+      <view class="opt-contain">
+        <view class="icon">
+          <i class="iconfont icon-shangchuanwenjian"></i>
+        </view>
+        <view class="tips">仅支持JPG、PNG、GIF、TXT、PDF、PPT、Excel、Word格式的文件,单个不超过10MB,多个不超过200MB</view>
+        <view class="btn" @click="selectFile()">上传文件</view>
+      </view>
+    </view>
+
+    <view v-else class="info-contain">
+      <view class="info-item file-list">
+        <view v-for="(item, index) of fileList"
+              :key="item.filePath"
+              class="file-item">
+          <view class="item-icon">
+            <!-- TODO: 优化为iconfont / css -->
+            <wd-img
+              :src="getFileIcon(item.name)"
+              :width="24"
+              :height="24"
+              mode="aspectFit"
+            ></wd-img>
+          </view>
+          <view class="item-name">{{ item.name }}</view>
+          <view class="item-opt" @click="previewFile(item.name, item.filePath)">预览</view>
+          <view class="item-opt color-danger" @click="removeFile(index)">移除</view>
+        </view>
+      </view>
+      <view class="info-item">
+        <!-- 选择打印机--获取打印参数--上传打印 -->
+        <wd-form ref="form" :model="formData">
+          <wd-cell-group custom-class="form-group">
+            <wd-select-picker
+              v-model="formData.printer"
+              label="打印机"
+              label-width="100px"
+              type="radio"
+              :columns="printerList"
+              value-key="id"
+              label-key="showName"
+              :max="1"
+              :show-confirm="false"
+              filterable
+              placeholder="请选择打印机"
+              prop="printer"
+              :rules="[{ required: true, message: '请选择打印机' }]"
+              @change="handlePrinterChange"
+            />
+            <!-- 动态属性 -->
+            <template v-for="option of printerOptions" :key="option.key">
+              <!-- type: select 下拉选项 -->
+              <wd-select-picker
+                v-if="option.type == 'select'"
+                v-model="formData[option.key]"
+                :label="option.text"
+                label-width="100px"
+                type="radio"
+                :columns="option.values"
+                value-key="key"
+                label-key="text"
+                :max="1"
+                :show-confirm="false"
+                filterable
+                :placeholder="`请选择${option.text}`"
+                :prop="option.key"
+                :rules="[{ required: true, message: `请选择${option.text}` }]"
               />
-            </view>
-          </wd-cell>
-          <!-- type: number 数字 -->
-          <wd-cell v-if="option.type == 'number'"
-                   :title="option.text"
-                   title-width="100px"
-                   custom-class="my-cell"
-                   :rules="[{ required: true, message: `请输入${option.text}` }]">
-            <wd-input-number v-model="formData[option.key]"
-                             :min="option.min"
-                             :max="option.max"
-                             :step="1"
-                             step-strictly
-                             input-width="100px" />
-          </wd-cell>
-        </template>
-      </wd-cell-group>
-
-      <view class="form-footer">
-        <wd-button type="primary" size="large" block @click="handleSubmit()">确认打印</wd-button>
+              <!-- type: radio 单选项 -->
+              <wd-cell v-if="option.type == 'radio'"
+                      :title="option.text"
+                      title-width="100px"
+                      custom-class="my-cell"
+                      :prop="option.key"
+                      :rules="[{ required: true, message: `请选择${option.text}` }]">
+                <wd-radio-group v-model="formData[option.key]"
+                                shape="dot"
+                                inline>
+                  <wd-radio v-for="item of option.values"
+                            :key="item.key"
+                            :value="item.key">
+                    {{ item.text }}
+                  </wd-radio>
+                </wd-radio-group>
+              </wd-cell>
+              <!-- type: rang 范围值, 传参是拼接字符串'xxx_str,xxx_end', 默认全部all不用传 -->
+              <wd-cell v-if="option.type == 'rang'"
+                      :title="option.text"
+                      title-width="100px"
+                      custom-class="my-cell"
+                      :prop="option.key"
+                      required>
+                <!-- 1. 先radio选择 all / range, 默认all全部, 仅单个文件时支持range选项 -->
+                <wd-radio-group v-model="formData[option.key]"
+                                shape="dot"
+                                inline>
+                  <wd-radio value="all">所有页</wd-radio>
+                  <wd-radio v-if="fileList.length == 1 && !isImg()" value="range">输入范围</wd-radio>
+                </wd-radio-group>
+                <!-- 2. 当上传单个文件(非图片)且radio选择 range 时允许输入范围, 从 XXX 到 XXX) -->
+                <view v-if="!isImg() && formData[option.key] == 'range'" style="text-align: left; margin-top: 10px">
+                  <view class="inline-txt" style="margin-left: 0">从</view>
+                  <wd-input
+                    custom-style="display: inline-block; width: 70px; vertical-align: middle"
+                    placeholder="起始页"
+                    v-model="formData[option.key + '_str']"
+                  />
+                  <view class="inline-txt">到</view>
+                  <wd-input
+                    custom-style="display: inline-block; width: 70px; vertical-align: middle"
+                    placeholder="结束页"
+                    v-model="formData[option.key + '_end']"
+                  />
+                </view>
+              </wd-cell>
+              <!-- type: number 数字 -->
+              <wd-cell v-if="option.type == 'number'"
+                      :title="option.text"
+                      title-width="100px"
+                      custom-class="my-cell"
+                      :rules="[{ required: true, message: `请输入${option.text}` }]">
+                <wd-input-number v-model="formData[option.key]"
+                                :min="option.min"
+                                :max="option.max"
+                                :step="1"
+                                step-strictly
+                                input-width="100px" />
+              </wd-cell>
+            </template>
+          </wd-cell-group>
+        </wd-form>
+
+        <view class="footer-btn">
+          <view class="btn light" @click="selectFile()">继续上传</view>
+          <view class="btn" @click="handleSubmit()">发送打印</view>
+        </view>
       </view>
-    </wd-form>    
+    </view> 
   </view>
 </template>
 
@@ -504,6 +530,7 @@ function selectFile() {
           console.log('chooseImage err: ', err);
           let tips = ['windows', 'mac'].includes(deviceInfo.platform) ? "已取消选择相册图片" : "选择相册图片失败, 请重试"
           switch (err.errMsg) {
+            case "chooseImage:fail":
             case "chooseImage:fail cancel":
               tips = "已取消选择相册图片"
               break;
@@ -665,18 +692,23 @@ function previewFile(fileName, filePath) {
 
 // 移除文件
 function removeFile(index) {
-  fileList.value.splice(index, 1)
-  handleFileListChange()
-  if (accept.value == "all" && fileList.value.length == 0) {
-    message.confirm({
-      msg: "文件已全部移除, 是否重新选择?",
-      closeOnClickModal: false,
-    }).then(() => {
-      redirectToUpload()
-    }).catch((error) => {
-      reLaunchToHome()
-    })
-  }
+  message.confirm({
+    msg: "是否移除该文件?",
+    closeOnClickModal: false,
+  }).then(() => {
+    fileList.value.splice(index, 1)
+    handleFileListChange()
+    if (accept.value == "all" && fileList.value.length == 0) {
+      message.confirm({
+        msg: "文件已全部移除, 是否重新选择?",
+        closeOnClickModal: false,
+      }).then(() => {
+        redirectToUpload()
+      }).catch((error) => {
+        reLaunchToHome()
+      })
+    }
+  }).catch(() => {})
 }
 
 // 批量打印文件
@@ -919,9 +951,75 @@ onLoad((option) => {
 </script>
 
 <style lang="scss" scoped>
-:deep(.my-cell) {
-  .wd-cell__value {
-    text-align: left !important;
+.page-form {
+  background-color: #fff;
+  padding-top: 0;
+  padding-left: 0;
+  padding-right: 0;
+
+  .guide-contain {
+    padding: 20rpx;
+  }
+
+  .info-contain {
+    .info-item {
+      border-top: 20rpx solid #F5F5F5;
+    }
+    .file-list {
+      padding: 20rpx;
+    }
+    .file-item {
+      display: flex;
+      align-items: center;
+      font-size: 26rpx;
+
+      .item-icon {
+        display: flex;
+        width: 48rpx;
+        height: 48rpx;
+        margin-right: 8rpx;
+      }
+      .item-name {
+        flex: 1;
+        word-break: break-all;
+      }
+      .item-opt {
+        display: flex;
+        width: 60rpx;
+        margin-left: 8rpx;
+        color: var(--wot-color-theme);
+      }
+    }
+    .file-item + .file-item {
+      margin-top: 20rpx;
+    }
+    .footer-btn {
+      position: fixed;
+      bottom: 0;
+      left: 0;
+      z-index: 10;
+      width: calc(100vw - 40rpx);
+      display: flex;
+      background-color: #fff;
+      padding: 20rpx;
+      .btn {
+        flex: 1;
+        text-align: center;
+        padding: 20rpx 0;
+        font-size: 36rpx;
+        border-radius: 44rpx;
+        color: #fff;
+        background-color: var(--wot-color-theme);
+      }
+      .btn.light {
+        color: var(--wot-color-theme);
+        background-color: #fff;
+        border: 2rpx solid var(--wot-color-theme);
+      }
+      .btn + .btn {
+        margin-left: 20rpx;
+      }
+    }
   }
 }
 
@@ -943,29 +1041,6 @@ onLoad((option) => {
   border-radius: 40rpx;
 }
 
-.file-item {
-  margin-bottom: 8rpx;
-  display: flex;
-  align-items: center;
-
-  .item-icon {
-    display: flex;
-    width: 40rpx;
-    height: 40rpx;
-    margin-right: 8rpx;
-  }
-  .item-name {
-    flex: 1;
-    word-break: break-all;
-  }
-  .item-del {
-    display: flex;
-    width: 40rpx;
-    height: 40rpx;
-    margin-left: 8rpx;
-  }
-}
-
 .inline-txt {
   display: inline-block;
   font-size: 28rpx;

+ 72 - 90
src/pages/print/job.vue

@@ -9,12 +9,13 @@
 <template>
   <view class="page-list">
     <wd-sticky>
-      <view class="sticky-box">
+      <view class="sticky-box" >
+        <!-- TODO: 优化固定的高度 -->
+        <view class="printer">{{ `当前打印机:${queryParams.printer || '全部'} ${queryParams.asname ? `(${queryParams.asname})` : ''}` }}</view>
         <wd-tabs v-model="queryParams.completed" auto-line-width @change="resetDataList">
           <wd-tab v-for="item of completedList" :key="item.value" :title="item.label" :name="item.value">
           </wd-tab>
         </wd-tabs>
-
         <!-- <wd-search
           placeholder="请输入打印任务名称"
           placeholder-left
@@ -33,40 +34,44 @@
     </wd-sticky>
 
     <view class="list-contain">
-      <view v-if="queryParams.printer" class="printer">{{ `当前打印机: ${queryParams.printer} ${queryParams.asname ? `(${queryParams.asname})` : ''}` }}</view>
-
       <template v-if="dataList.length > 0 || loadStatus == 'loading'">
-        <view v-for="item of dataList" :key="item.id" class="item-contain" @click="toDetail(item)">
-          <view class="item-info">
-            <view class="image">
+        <view v-for="item of dataList" :key="item.id" class="item-box" @click="toDetail(item)">
+          <view class="info-box">
+            <view class="icon">
+              <!-- TODO: 优化为样式实现 较少图片引入 -->
               <wd-img
                 :src="getFileType(item.title)"
-                :width="60"
-                :height="60"
+                :width="40"
+                :height="40"
                 mode="aspectFit"
               ></wd-img>
             </view>
-            <view class="name">
+            <view class="info">
               <view class="main-text">
-                <view>{{ item.title }}</view>
+                <view class="name">{{ item.title }}</view>
+                <view class="tag" :class="`${getLabelColor(item.jobStatus, jobStatus)}`">
+                  {{ getLabel(item.jobStatus, jobStatus) }}
+                </view>
               </view>
-              <view class="sub-text">
-                <text>任务状态: </text>
-                <text :class="`color-${getLabelColor(item.jobStatus, jobStatus)}`">{{ getLabel(item.jobStatus, jobStatus) + (item.statusMsg ? `(${item.statusMsg})` : "") }}</text>
+              <view v-if="item.statusMsg" class="sub-text">
+                <view class="label">状态描述:</view>
+                <view class="value">{{ item.statusMsg }} </view>
               </view>
               <view class="sub-text">
-                {{ `创建时间: ${item.createTime}` }}
+                <view class="label">创建时间:</view>
+                <view class="value">{{ item.createTime }} </view>
               </view>
-              <!-- <view class="sub-text flex-center">
-                <view class="flex-1">xxx</view>
-                <view class="flex-1">xxx</view>
-              </view> -->
             </view>
           </view>
-          <view class="item-opt">
-            <view v-if="item.reprint == '1'" class="opt-btn" @click.stop="handleReprint(item.id)">重打</view>
-            <view v-if="['3', '4', '5', '6'].includes(item.jobStatus)" class="opt-btn" @click.stop="handleCancel(item.id)">取消</view>
-            <view class="opt-btn delete-btn" @click.stop="handleDelete(item)">删除</view>
+          <view class="opt-box">
+            <view v-if="item.reprint == '1'"
+                  class="opt-circle-btn"
+                  @click.stop="handleReprint(item.id)">重打</view>
+            <view v-if="['3', '4', '5', '6'].includes(item.jobStatus)"
+                  class="opt-circle-btn waring"
+                  @click.stop="handleCancel(item.id)">取消</view>
+            <view class="opt-circle-btn danger"
+                  @click.stop="handleDelete(item)">移除</view>
           </view>
         </view>
         <!-- 加载更多 -->
@@ -108,8 +113,8 @@ const completedList: any = ref([
 //  0连接中 3 等待中 4 已暂停 5 处理中 6已停止 7已取消 8已中止 9已完成
 const jobStatus: any = ref([
   { label: '连接中', value: '0', color: 'primary' },
-  { label: '等待中', value: '3', color: 'info' },
-  { label: '已暂停', value: '4', color: 'info' },
+  { label: '等待中', value: '3', color: 'gray' },
+  { label: '已暂停', value: '4', color: 'gray' },
   { label: '处理中', value: '5', color: 'primary' },
   { label: '已停止', value: '6', color: 'danger' },
   { label: '已取消', value: '7', color: 'danger' },
@@ -250,18 +255,18 @@ function handleCancel(id: string) {
   })
 }
 
-// 除任务
+// 除任务
 function handleDelete(item) {
   message
     .confirm({
       title: '提示',
-      msg: `是否除打印任务: ${item.title} ?`,
+      msg: `是否除打印任务: ${item.title} ?`,
     })
     .then(() => {
       deleteUserHubJobs({id: item.id})
         .then((res: any) => {
           if (res.code === 0) {
-            toast.success('除成功')
+            toast.success('除成功')
             queryParams.pageNo = 1
             getDataList()
           }
@@ -461,7 +466,7 @@ function handleUpdate(data) {
 <style lang="scss" scoped>
 .sticky-box {
   width: 100vw;
-  height: 100rpx;
+  height: 140rpx;
   background-color: #ffffff;
 }
 .search-type {
@@ -486,80 +491,57 @@ function handleUpdate(data) {
     vertical-align: middle;
   }
 }
+//搜索下拉菜单
+:deep(.search-menu .wd-drop-menu__list) {
+  background: none;
+}
+:deep(.search-menu .wd-drop-menu__item) {
+  height: 62rpx;
+  line-height: 62rpx;
+}
+:deep(.search-menu .wd-drop-menu__item-title::after) {
+  content: none;
+}
+// 当前打印机
 .printer {
-  margin-bottom: 20rpx;
+  padding: 20rpx 20rpx 0;
 }
+.page-list {
+  background-color: #F5F5F5;
+}
+// 列表
 .list-contain {
-  padding: 10rpx 30rpx 30rpx;
+  padding: 20rpx 20rpx 20rpx;
   overflow-y: auto;
 
-  .item-contain {
-    padding: 30rpx;
-    margin-bottom: 30rpx;
-    border: 2rpx solid #eee;
-
-    .item-info {
-      display: flex;
-      align-items: flex-start;
-      .image {
-        display: flex;
-        padding-right: 14rpx;
+  .item-box {
+    padding: 0;
+    background-color: #ffffff;
+    border: unset;
+
+    .info-box {
+      padding: 20rpx;
+      .icon {
+        margin-right: 20rpx;
       }
-      .name {
-        flex: 1;
-        .main-text {
-          display: flex;
-          align-items: center;
-          word-break: break-all;
-        }
+      .info {
         .sub-text {
-          margin-top: 14rpx;
-          font-size: 28rpx;
-          color: #00000073;
+          color: #666666;
+          display: flex;
+          .value {
+            flex: 1;
+          }
         }
       }
-      .opt {
-        width: 80rpx;
-        text-align: center;
-      }
     }
-
-    .item-opt {
-      margin-top: 20rpx;
-      border-top: 2rpx solid #eee;
-      padding-top: 20rpx;
-      text-align: right;
-      font-size: 28rpx;
-      
-      .opt-btn {
-        display: inline-block;
-        padding: 4rpx 20rpx;
-        margin-left: 20rpx;
-        color: var(--wot-color-theme);
-        border: 2rpx solid var(--wot-color-theme);
-        border-radius: 8rpx;
-      }
-      .opt-btn:first-of-type {
-        margin-left: 0;
-      }
-      .delete-btn {
-        color: #fa4350;
-        border-color: #fa4350;
-      }
+    .opt-box {
+      border-top: 2rpx solid #EBEBEB;
+      padding: 20rpx;
+      margin-top: 0;
     }
   }
 }
-//搜索下拉菜单
-:deep(.search-menu .wd-drop-menu__list) {
-  background: none;
-}
-:deep(.search-menu .wd-drop-menu__item) {
-  height: 62rpx;
-  line-height: 62rpx;
-}
-:deep(.search-menu .wd-drop-menu__item-title::after) {
-  content: none;
-}
+// 弹窗内容换行
 :deep(.wd-message-box__content) {
   word-break: break-all;
 }

+ 67 - 85
src/pages/print/jobForIntranet.vue

@@ -10,11 +10,12 @@
   <view class="page-list">
     <wd-sticky>
       <view class="sticky-box">
+        <!-- TODO: 优化固定的高度 -->
+        <view v-if="queryParams.printer" class="printer">{{ `当前打印机: ${queryParams.printer || '全部'} ${queryParams.asname ? `(${queryParams.asname})` : ''}` }}</view>
         <wd-tabs v-model="queryParams.completed" auto-line-width @change="resetDataList">
           <wd-tab v-for="item of completedList" :key="item.value" :title="item.label" :name="item.value">
           </wd-tab>
         </wd-tabs>
-
         <!-- <wd-search
           placeholder="请输入打印任务名称"
           placeholder-left
@@ -33,40 +34,44 @@
     </wd-sticky>
 
     <view class="list-contain">
-      <view v-if="queryParams.printer" class="printer">{{ `当前打印机: ${queryParams.printer} ${queryParams.asname ? `(${queryParams.asname})` : ''}` }}</view>
-
       <template v-if="dataList.length > 0 || loadStatus == 'loading'">
-        <view v-for="item of dataList" :key="item.id" class="item-contain">
-          <view class="item-info">
-            <view class="image">
+        <view v-for="item of dataList" :key="item.id" class="item-box">
+          <view class="info-box">
+            <view class="icon">
+              <!-- TODO: 优化为样式实现 较少图片引入 -->
               <wd-img
                 :src="getFileType(item['document-name-supplied'])"
-                :width="60"
-                :height="60"
+                :width="40"
+                :height="40"
                 mode="aspectFit"
               ></wd-img>
             </view>
-            <view class="name">
+            <view class="info">
               <view class="main-text">
-                <view>{{ item['document-name-supplied'] }}</view>
+                <view class="name">{{ item['document-name-supplied'] }}</view>
+                <view class="tag" :class="`${getLabelColor(item['job-state'], jobStatus)}`">
+                  {{ getLabel(item['job-state'], jobStatus) }}
+                </view>
               </view>
-              <view class="sub-text">
-                <text>任务状态: </text>
-                <text :class="`color-${getLabelColor(item['job-state'], jobStatus)}`">{{ getLabel(item['job-state'], jobStatus) + (item['job-printer-state-message'] ? `(${item['job-printer-state-message']})` : "") }}</text>
+              <view v-if="item['job-printer-state-message']" class="sub-text">
+                <view class="label">状态描述:</view>
+                <view class="value">{{ item['job-printer-state-message'] }} </view>
               </view>
               <view class="sub-text">
-                {{ `创建时间: ${timestampToDatetime(item['time-at-creation'])}` }}
+                <view class="label">创建时间:</view>
+                <view class="value">{{ timestampToDatetime(item['time-at-creation']) }}</view>
               </view>
-              <!-- <view class="sub-text flex-center">
-                <view class="flex-1">xxx</view>
-                <view class="flex-1">xxx</view>
-              </view> -->
             </view>
           </view>
-          <view class="item-opt">
+          <view v-if="(item['job-state'] == 9 && item['number-of-documents']) || [3, 4, 5, 6].includes(item['job-state'])"
+                class="opt-box">
             <!-- 移动, 重打, 挂起, 恢复, 取消 -->
-            <view v-if="item['job-state'] == 9 && item['number-of-documents']" class="opt-btn" @click.stop="handleReprint(item['job-id'])">重打</view>
-            <view v-if="[3, 4, 5, 6].includes(item['job-state'])" class="opt-btn" @click.stop="handleCancel(item['job-id'])">取消</view>
+            <view v-if="item['job-state'] == 9 && item['number-of-documents']"
+                  class="opt-circle-btn"
+                  @click.stop="handleReprint(item['job-id'])">重打</view>
+            <view v-if="[3, 4, 5, 6].includes(item['job-state'])"
+                  class="opt-circle-btn danger"
+                  @click.stop="handleCancel(item['job-id'])">取消</view>
           </view>
         </view>
         <!-- 加载更多 -->
@@ -105,8 +110,8 @@ const completedList: any = ref([
 //  0连接中 3 等待中 4 已暂停 5 处理中 6已停止 7已取消 8已中止 9已完成
 const jobStatus: any = ref([
   { label: '连接中', value: '0', color: 'primary' },
-  { label: '等待中', value: '3', color: 'info' },
-  { label: '已暂停', value: '4', color: 'info' },
+  { label: '等待中', value: '3', color: 'gray' },
+  { label: '已暂停', value: '4', color: 'gray' },
   { label: '处理中', value: '5', color: 'primary' },
   { label: '已停止', value: '6', color: 'danger' },
   { label: '已取消', value: '7', color: 'danger' },
@@ -217,7 +222,7 @@ function getDataListNotCompleted(uri) {
   })
 }
 
-// 已经完成的打印任务 (前端分页)
+// 已经完成的打印任务 (TODO: 前端分页)
 function getDataListCompleted(uri) {
   let params = {
     "ip": intranetIp.value,
@@ -330,7 +335,7 @@ onReachBottom(() => {
 <style lang="scss" scoped>
 .sticky-box {
   width: 100vw;
-  height: 100rpx;
+  height: 140rpx;
   background-color: #ffffff;
 }
 .search-type {
@@ -355,80 +360,57 @@ onReachBottom(() => {
     vertical-align: middle;
   }
 }
+//搜索下拉菜单
+:deep(.search-menu .wd-drop-menu__list) {
+  background: none;
+}
+:deep(.search-menu .wd-drop-menu__item) {
+  height: 62rpx;
+  line-height: 62rpx;
+}
+:deep(.search-menu .wd-drop-menu__item-title::after) {
+  content: none;
+}
+// 当前打印机
 .printer {
-  margin-bottom: 20rpx;
+  padding: 20rpx 20rpx 0;
+}
+.page-list {
+  background-color: #F5F5F5;
 }
+// 列表
 .list-contain {
-  padding: 10rpx 30rpx 30rpx;
+  padding: 20rpx 20rpx 20rpx;
   overflow-y: auto;
 
-  .item-contain {
-    padding: 30rpx;
-    margin-bottom: 30rpx;
-    border: 2rpx solid #eee;
+  .item-box {
+    padding: 0;
+    background-color: #ffffff;
+    border: unset;
 
-    .item-info {
-      display: flex;
-      align-items: flex-start;
-      .image {
-        display: flex;
-        padding-right: 14rpx;
+    .info-box {
+      padding: 20rpx;
+      .icon {
+        margin-right: 20rpx;
       }
-      .name {
-        flex: 1;
-        .main-text {
-          display: flex;
-          align-items: center;
-          word-break: break-all;
-        }
+      .info {
         .sub-text {
-          margin-top: 14rpx;
-          font-size: 28rpx;
-          color: #00000073;
+          color: #666666;
+          display: flex;
+          .value {
+            flex: 1;
+          }
         }
       }
-      .opt {
-        width: 80rpx;
-        text-align: center;
-      }
     }
-
-    .item-opt {
-      margin-top: 20rpx;
-      border-top: 2rpx solid #eee;
-      padding-top: 20rpx;
-      text-align: right;
-      font-size: 28rpx;
-      
-      .opt-btn {
-        display: inline-block;
-        padding: 4rpx 20rpx;
-        margin-left: 20rpx;
-        color: var(--wot-color-theme);
-        border: 2rpx solid var(--wot-color-theme);
-        border-radius: 8rpx;
-      }
-      .opt-btn:first-of-type {
-        margin-left: 0;
-      }
-      .delete-btn {
-        color: #fa4350;
-        border-color: #fa4350;
-      }
+    .opt-box {
+      border-top: 2rpx solid #EBEBEB;
+      padding: 20rpx;
+      margin-top: 0;
     }
   }
 }
-//搜索下拉菜单
-:deep(.search-menu .wd-drop-menu__list) {
-  background: none;
-}
-:deep(.search-menu .wd-drop-menu__item) {
-  height: 62rpx;
-  line-height: 62rpx;
-}
-:deep(.search-menu .wd-drop-menu__item-title::after) {
-  content: none;
-}
+// 弹窗内容换行
 :deep(.wd-message-box__content) {
   word-break: break-all;
 }

+ 60 - 78
src/pages/printer/index.vue

@@ -2,7 +2,7 @@
 <route lang="json5">
 {
   style: {
-    navigationBarTitleText: '打印机列表',
+    navigationBarTitleText: '已关联打印机列表',
   },
 }
 </route>
@@ -29,40 +29,44 @@
 
     <view class="list-contain">
       <template v-if="dataList.length > 0 || loadStatus == 'loading'">
-        <view v-for="item of dataList" :key="item.id" class="list-box">
-          <view class="name">
-            <view class="main-text">
-              <view>{{ item.name }}</view>
-              <wd-tag :type="item.enable == '0' ? 'danger' : 'success'" mark custom-class="ml-2">
-                {{ getLabel(item.enable, statusList) }}
-              </wd-tag>
+        <view v-for="item of dataList" :key="item.id" class="item-box">
+          <view class="info-box">
+            <!-- 如果左侧icon, 使用如下 -->
+            <!-- <view class="icon"></view> -->
+            <view class="info">
+              <view class="main-text">
+                <view class="name">
+                  <text>{{ item.name }}</text>
+                  <text class="status">{{ ` (${getLabel(item['printer-state'], printerStatus)})` }}</text>
+                </view>
+                <view class="tag" :class="item.enable == '0' ? 'danger' : 'success'">
+                  {{ getLabel(item.enable, statusList) }}
+                </view>
+              </view>
+              <view class="sub-text">
+                <view class="label">品牌型号:</view>
+                <view class="value">{{ item['printer-make-and-model'] }}</view>
+              </view>
+              <view v-if="item['printer-state-message']" class="sub-text">
+                <view class="label">状态描述:</view>
+                <view class="value">{{ item['printer-state-message'] }}</view>
+              </view>
             </view>
-            <view class="sub-text">
-              {{ `品牌型号: ${item['printer-make-and-model']}` }}
+          </view>
+          <view class="opt-box">
+            <view class="opt-circle-btn" @click.stop="toJob(item)">
+              打印任务
             </view>
-            <view class="sub-text">
-              <text>{{ `状态: ${getLabel(item['printer-state'], printerStatus)} ` }}</text>
-              <text v-if="item['printer-state-message']" class="text-italic">{{ item['printer-state-message'] }}</text>
+            <view v-if="intranetIp" class="opt-circle-btn" @click.stop="toIntranetJob(item)">
+              局域网打印任务
             </view>
           </view>
-          <view class="opt" @click.stop="showActions(item)">
-            <wd-button type="icon" icon="more"></wd-button>
-          </view>
         </view>
         <!-- 加载更多 -->
         <wd-loadmore custom-class="loadmore" :state="loadStatus" />
       </template>
       <wd-status-tip v-else image="content" tip="暂无内容" />
     </view>
-
-    <!-- 动作面板 -->
-    <wd-action-sheet
-      v-model="isShowActions"
-      :actions="currentActions"
-      :title="actionsTitle"
-      @close="isShowActions = false"
-      @select="selectActions"
-    />
   </view>
 </template>
 
@@ -91,13 +95,8 @@ const printerStatus: any = ref([
   { label: '忙碌', value: '1290' }
 ])
 const dataList = ref([])
-const currentData: any = ref({})
 // 加载中: loading; 没有数据: finished; 错误: error;
 const loadStatus: any = ref('loading')
-// 动作面板
-const isShowActions = ref(false)
-const actionsTitle = ref('')
-const currentActions: any = ref([{ loading: true }])
 const isToTop = ref(false)
 // 判断环境是否局域网
 const intranetIp = ref("")
@@ -106,16 +105,6 @@ defineOptions({
   name: 'Printer',
 })
 
-// 根据状态 构造操作面板
-function buildCurrentActions() {
-  currentActions.value = [
-    { name: '查看打印任务' },
-  ]
-  if (intranetIp.value && intranetIp.value != 'undefined') {
-    currentActions.value.push({ name: '查看局域网打印任务' })
-  }
-}
-
 function getDataList() {
   loadStatus.value = 'loading'
   const params = { ...queryParams }
@@ -156,24 +145,6 @@ function toIntranetJob(data?: any) {
   })
 }
 
-function showActions(data: any) {
-  actionsTitle.value = data.name ? `打印机: ${data.name}` : '操作'
-  currentData.value = data || {}
-  buildCurrentActions()
-  isShowActions.value = true
-}
-
-function selectActions(data: any) {
-  switch (data.item.name) {
-    case '查看打印任务':
-      toJob(currentData.value)
-      break;
-    case '查看局域网打印任务':
-      toIntranetJob(currentData.value)
-      break;
-  }
-}
-
 // 查询列表, 滚动到顶部, 返回第一页
 function resetDataList() {
   uni.pageScrollTo({
@@ -243,32 +214,43 @@ onReachBottom(() => {
     vertical-align: middle;
   }
 }
+.page-list {
+  background-color: #F5F5F5;
+}
 .list-contain {
-  padding: 10rpx 30rpx 30rpx;
+  padding: 20rpx 20rpx 20rpx;
   overflow-y: auto;
 
-  .list-box {
-    display: flex;
-    align-items: center;
-    padding: 30rpx 0 30rpx 30rpx;
-    margin-bottom: 30rpx;
-    border: 1px solid #eee;
+  .item-box {
+    padding: 0;
+    background-color: #fff;
+    border: unset;
 
-    .name {
-      flex: 1;
-      .main-text {
-        display: flex;
-        align-items: center;
-      }
-      .sub-text {
-        margin-top: 20rpx;
-        font-size: 28rpx;
-        color: #00000073;
+    .info-box {
+      padding: 20rpx;
+      .info {
+        .main-text {
+          .name {
+            .status {
+              color: #666666;
+              font-size: 24rpx;
+            }
+          }
+        }
+        .sub-text {
+          margin-top: 20rpx;
+          color: #666666;
+          display: flex;
+          .value {
+            flex: 1;
+          }
+        }
       }
     }
-    .opt {
-      width: 80rpx;
-      text-align: center;
+    .opt-box {
+      border-top: 2rpx solid #EBEBEB;
+      padding: 20rpx;
+      margin-top: 0;
     }
   }
 }

+ 0 - 177
src/pages/test/index.vue

@@ -1,177 +0,0 @@
-
-<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
-<route lang="json5">
-{
-  style: {
-    navigationBarTitleText: '测试页',
-  },
-}
-</route>
-<template>
-  <view class="page-form">
-    <!-- 选择打印机--获取打印参数--上传打印 -->
-    <wd-form ref="form" :model="formData">
-      <wd-cell-group custom-class="form-group" border>
-        <wd-cell title="文件"
-                 title-width="100px"
-                 required>
-          <wd-button @click="getFromMsg">聊天窗口</wd-button>
-        </wd-cell>
-
-        <wd-cell title="文件"
-                 title-width="100px"
-                 required>
-          <wd-button @click="getFromImage">相册&相机</wd-button>
-        </wd-cell>
-
-        <wd-cell title="文件"
-                 title-width="100px"
-                 required>
-          <wd-button @click="openWebView">webview</wd-button>
-        </wd-cell>
-
-        <wd-cell title="发票"
-                 title-width="100px"
-                 required>
-          <wd-button @click="getInvoice">测试</wd-button>
-        </wd-cell>
-        
-        <wd-cell title="SSE"
-                 title-width="100px"
-                 required>
-          <wd-button @click="openWebViewSSE">webview</wd-button>
-        </wd-cell>
-      </wd-cell-group>
-    </wd-form>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { useToast, useMessage } from 'wot-design-uni'
-import { useUserStore } from '@/store'
-
-const userStore = useUserStore()
-const formData = ref({})
-
-// 从本地选择文件 -- uniclound 插件市场
-// https://ext.dcloud.net.cn/plugin?id=12245
-// https://ext.dcloud.net.cn/plugin?id=5459
-// https://ext.dcloud.net.cn/plugin?id=12526
-
-// 从本地选择文件 -- uni.chooseFile(OBJECT) (小程序不支持, 仅uniapp h5页面)
-// https://uniapp.dcloud.net.cn/api/media/file.html
-
-
-/**
- * 聊天窗口 可指定参数
- * https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseMessageFile.html
- * 
- * 	count	最多可以选择的文件个数,可以 0~100
- * 
- *  type  所选的文件的类型	
- *    all	从所有文件选择
- *    video	只能选择视频文件
- *    image	只能选择图片文件
- *    file	可以选择除了图片和视频之外的其它的文件
- * 
- *  extension 根据文件拓展名过滤,仅 type==file 时有效。每一项都不能是空字符串。默认不过滤。
- *  
- *  success
- *  fail
- *  complete
- */
-function getFromMsg() {
-  uni.chooseMessageFile({
-    count: 1,
-    type: "all",
-    success (res) {
-      console.log('chooseMessageFile res: ', res);
-      // tempFilePath可以作为img标签的src属性显示图片
-      const tempFilePaths = res.tempFiles
-    }
-  })
-}
-
-/**
- * 从本地相册选择图片或使用相机拍照。
- * https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage
- * https://uniapp.dcloud.net.cn/api/media/video.html#choosemedia
- * 
- * 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
- * 
- * count	最多可以选择的文件个数,可以 0~100
- * 
- * sourceType  数组  ['album', 'camera'] album 从相册选图,camera 使用相机,默认二者都有。如需直接开相机或直接选相册,请只使用一个选项
- * 
- * sizeType  数组  ['original', 'compressed']	 original 原图,compressed 压缩图,默认二者都有
- * 
- * 【chooseimage】 extension  数组  根据文件拓展名过滤,每一项都不能是空字符串。默认不过滤。
- * 
- * 【chooseimage】 crop 对象  图像裁剪参数,设置后 sizeType 失效	
- * 
- * 【chooseMedia】 mediaType  数组  ['image', 'video']  文件类型
- * 
- * 【chooseMedia】 camera	String	'back'	仅在 sourceType 为 camera 时生效,使用前置或后置摄像头
- * 
- * 【chooseMedia】 maxDuration    拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间
- * 
- *  success
- *  fail
- *  complete
- */
-function getFromImage() {
-  uni.chooseImage({
-    count: 1,
-    sourceType: ['album', 'camera'],
-    sizeType: ['original', 'compressed'],
-    extension: ['png', 'jpg', 'jpeg', 'gif', 'webp'],
-    success (res) {
-      console.log('chooseImage res: ', res);
-      // tempFilePath可以作为img标签的src属性显示图片
-      const tempFilePaths = res.tempFiles
-    }
-  })
-}
-
-// 通过 webview 选择系统文件
-function openWebView() {
-  // https://blog.csdn.net/qq_60208156/article/details/132578144
-  // https://dandelioncloud.cn/article/details/1613831738646298625
-  const url = "https://service.1ai.ltd/webview-upload/index.html"
-  uni.navigateTo({
-    url: `/pages/webview/index?url=${encodeURIComponent(url)}`,
-  })
-}
-
-// 获取发票信息后 再调用接口获取 pdf_url
-function getInvoice() {
-  // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/invoice/wx.chooseInvoice.html
-  // https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Reimburser_API_List.html#5
-  uni.chooseInvoice({
-    success (res) {
-      console.log('chooseInvoice res: ', res);
-      // invoiceInfo	用户选中的发票信息,格式为一个 JSON 字符串,包含三个字段: 
-      //    card_id:所选发票卡券的 cardId,
-      //    encrypt_code:所选发票卡券的加密 code,报销方可以通过 cardId 和 encryptCode 获得报销发票的信息,
-      //    app_id: 发票方的 appId
-    }
-  })
-}
-
-// 通过 webview 创建sse
-function openWebViewSSE() {
-  const token = userStore.token
-  const list = JSON.stringify([])
-  const url = `https://service.1ai.ltd/webview-sse/index.html?token=${token}&list=${list}&t=${new Date().getTime()}`
-  uni.navigateTo({
-    url: `/pages/webview/sse?url=${encodeURIComponent(url)}`,
-  })
-}
-
-onLoad(() => {
-  
-})
-</script>
-
-<style lang="scss" scoped>
-</style>

+ 0 - 110
src/pages/webview/sse.vue

@@ -1,110 +0,0 @@
-<route lang="json5" type="page">
-{
-  layout: 'default',
-  style: {
-    navigationBarTitleText: '查看打印任务',
-  },
-}
-</route>
-
-<template>
-  <view class="">
-    <web-view :src="webviewUrl" ref="webviewRef" id="myWebView"></web-view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-const webviewUrl = ref("")
-const webviewRef = ref()
-const webViewContext = ref(null);
-
-// 双向通信 fail、--- 小程序环境evalJS不支持
-// URL参数 fail、---不能实时
-// WebSocket 、--- 需要服务端搭建
-// 全局事件 --- 待尝试
-
-
-// 方法1 (fail): 创建webviewContent
-// 这个uni.createWebviewContext 是 uni-app-x 的api .在uni-app中不能用
-
-// 方法1 (fail): 创建webviewContent 使用 evalJs 通信 (原生APP可以使用 evalJS, 小程序不行)
-// const webViewContext = uni.createWebviewContext('sse')
-// webViewContext.evalJS(`handleAppMsg('这是来自小程序的消息')`)
-
-// function sendToWebview() {
-//   let data = "这是来自App原生的消息"
-//   webviewRef.value.evalJS(`handleAppMsg(${data})`)
-// }
-
-// 方法2: 创建websocket与webview进行通信
-// 在打印列表页创建websocket 与 webview--连接
-// function connectSocket() {
-//   const socket: any = uni.connectSocket({
-//     url: 'wss://service.1ai.ltd',
-//     success: () => {
-//       console.log("连接成功111");
-//     },
-//     fail: (err) => {
-//       console.log("连接失败222");
-//     }
-//   })
-//   console.log('socket: ', socket);
-//   socket.onMessage((res) => {
-//     console.log('Received message:', res.data);
-//   });
-
-//   setInterval(() => {
-//     console.log("send");
-//     socket.send({
-//       data: JSON.stringify({ type: 'notify', content: 'Hello from Mini Program!' })
-//     })
-//   }, 5000)
-// }
-
-// 方法3: postmessage --- createWebViewContext 该方法不存在
-// function postMessage() {
-//   uni.createWebViewContext('myWebView').then(context => {
-//     webViewContext.value = context;
-//     console.log('WebView 上下文获取成功', webViewContext.value);
-//     // 现在你可以使用 context 对象来操作 WebView 了
-//     // 例如:context.evaluateJavaScript('document.title')
-//   }).catch(err => {
-//     console.error('获取 WebView 上下文失败', err);
-//   });
-
-//   setInterval(() => {
-//     // webviewRef.value.postMessage({ data: 'Hello from Mini Program!' })
-//     console.log('webviewRef: ', webviewRef.value);
-//   }, 3000)
-// }
-
-
-
-
-onLoad((option) => {
-  if (option && option.url) webviewUrl.value = decodeURIComponent(option.url) + "#s=111"
-
-  // uni.$on('webviewEvent', (data) => {
-  //   console.log('收到 WebView 事件:', data);
-  // });
-
-  // setTimeout(() => {
-  //   console.log("小程序发送全局事件 miniProgramEvent");
-  //   uni.$emit('miniProgramEvent', { data: '来自小程序的数据' });
-  // }, 3000)
-
-  // uni.setStorageSync("toWebView", '初始值')
-
-  setInterval(() => {
-    // console.log('uni.getStorageSync("toWebView"): ', uni.getStorageSync("toWebView"));
-    // console.log('uni.getStorageSync("toApp"): ', uni.getStorageSync("toApp"));
-    
-    let s = new Date().getTime()
-    console.log("s:", s);
-    webviewUrl.value = decodeURIComponent(option.url) + "#s=" + s
-  }, 3000)
-})
-</script>
-
-<style lang="scss" scoped>
-</style>

Plik diff jest za duży
+ 112 - 0
src/static/iconfont/iconfont.css


Plik diff jest za duży
+ 1 - 0
src/static/iconfont/iconfont.js


+ 177 - 0
src/static/iconfont/iconfont.json

@@ -0,0 +1,177 @@
+{
+  "id": "4870026",
+  "name": "maoer",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "猫耳云打印小程序",
+  "glyphs": [
+    {
+      "icon_id": "8288873",
+      "name": "设置",
+      "font_class": "shezhi",
+      "unicode": "e851",
+      "unicode_decimal": 59473
+    },
+    {
+      "icon_id": "43777129",
+      "name": "combined",
+      "font_class": "combined",
+      "unicode": "e608",
+      "unicode_decimal": 58888
+    },
+    {
+      "icon_id": "1081852",
+      "name": "Internet",
+      "font_class": "internet",
+      "unicode": "e63b",
+      "unicode_decimal": 58939
+    },
+    {
+      "icon_id": "1090745",
+      "name": "设备",
+      "font_class": "icon",
+      "unicode": "e69a",
+      "unicode_decimal": 59034
+    },
+    {
+      "icon_id": "2398089",
+      "name": "手机WiFi",
+      "font_class": "shoujiWiFi",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
+    },
+    {
+      "icon_id": "6177856",
+      "name": "开具发票",
+      "font_class": "kaijufapiao",
+      "unicode": "e603",
+      "unicode_decimal": 58883
+    },
+    {
+      "icon_id": "6893981",
+      "name": "设备",
+      "font_class": "shebei",
+      "unicode": "e6c9",
+      "unicode_decimal": 59081
+    },
+    {
+      "icon_id": "7525578",
+      "name": "下一步",
+      "font_class": "xiayibu",
+      "unicode": "e600",
+      "unicode_decimal": 58880
+    },
+    {
+      "icon_id": "8157844",
+      "name": "打印设置",
+      "font_class": "dayinshezhi",
+      "unicode": "e631",
+      "unicode_decimal": 58929
+    },
+    {
+      "icon_id": "8507595",
+      "name": "设备",
+      "font_class": "icon1",
+      "unicode": "e601",
+      "unicode_decimal": 58881
+    },
+    {
+      "icon_id": "8722594",
+      "name": "温馨提示",
+      "font_class": "wenxintishi",
+      "unicode": "e642",
+      "unicode_decimal": 58946
+    },
+    {
+      "icon_id": "10617808",
+      "name": "网络",
+      "font_class": "wangluo",
+      "unicode": "e6c0",
+      "unicode_decimal": 59072
+    },
+    {
+      "icon_id": "11372685",
+      "name": "扫一扫",
+      "font_class": "saoyisao",
+      "unicode": "e8b5",
+      "unicode_decimal": 59573
+    },
+    {
+      "icon_id": "20592561",
+      "name": "online",
+      "font_class": "online",
+      "unicode": "e602",
+      "unicode_decimal": 58882
+    },
+    {
+      "icon_id": "20912773",
+      "name": "下一步",
+      "font_class": "xiayibu2",
+      "unicode": "e604",
+      "unicode_decimal": 58884
+    },
+    {
+      "icon_id": "22430767",
+      "name": "任务列表",
+      "font_class": "renwu",
+      "unicode": "e605",
+      "unicode_decimal": 58885
+    },
+    {
+      "icon_id": "23773326",
+      "name": "设备",
+      "font_class": "shebei1",
+      "unicode": "e74f",
+      "unicode_decimal": 59215
+    },
+    {
+      "icon_id": "24111744",
+      "name": "图片",
+      "font_class": "tupian",
+      "unicode": "fb84",
+      "unicode_decimal": 64388
+    },
+    {
+      "icon_id": "25042155",
+      "name": "cloud",
+      "font_class": "cloud",
+      "unicode": "e714",
+      "unicode_decimal": 59156
+    },
+    {
+      "icon_id": "26063305",
+      "name": "打印完成",
+      "font_class": "dayinwancheng",
+      "unicode": "e606",
+      "unicode_decimal": 58886
+    },
+    {
+      "icon_id": "26725650",
+      "name": "上传文件",
+      "font_class": "shangchuanwenjian",
+      "unicode": "e607",
+      "unicode_decimal": 58887
+    },
+    {
+      "icon_id": "33987020",
+      "name": "分享 2",
+      "font_class": "a-fenxiang2",
+      "unicode": "e620",
+      "unicode_decimal": 58912
+    },
+    {
+      "icon_id": "37664769",
+      "name": "文档",
+      "font_class": "wendang",
+      "unicode": "e63e",
+      "unicode_decimal": 58942
+    },
+    {
+      "icon_id": "41795249",
+      "name": "打印机",
+      "font_class": "a-printer",
+      "unicode": "e637",
+      "unicode_decimal": 58935
+    }
+  ]
+}

BIN
src/static/iconfont/iconfont.ttf


BIN
src/static/iconfont/iconfont.woff


BIN
src/static/iconfont/iconfont.woff2


BIN
src/static/images/avatar.png


BIN
src/static/images/connect.png


BIN
src/static/images/document.png


BIN
src/static/images/file.png


BIN
src/static/images/history.png


BIN
src/static/images/icon/album.png


BIN
src/static/images/icon/cards.png


BIN
src/static/images/icon/connect.png


BIN
src/static/images/icon/file.png


BIN
src/static/images/icon/folder-close.png


BIN
src/static/images/icon/folder-open.png


BIN
src/static/images/icon/history-query.png


BIN
src/static/images/icon/message.png


BIN
src/static/images/icon/picture.png


BIN
src/static/images/icon/printer-two.png


BIN
src/static/images/icon/printer.png


BIN
src/static/images/icon/wechat.png


BIN
src/static/images/invoice.png


BIN
src/static/images/logo_temp.png


BIN
src/static/images/logo_temp1.png


BIN
src/static/images/logo_top.png


BIN
src/static/images/picture.png


BIN
src/static/images/share.png


BIN
src/static/images/wechatFile.png


BIN
src/static/images/wechat_file.png


BIN
src/static/images/wechat_invoice.png


Plik diff jest za duży
+ 0 - 33
src/static/logo.svg


BIN
src/static/tabbar/device.png


BIN
src/static/tabbar/deviceHL.png


BIN
src/static/tabbar/homeHL.png


BIN
src/static/tabbar/personalHL.png


Plik diff jest za duży
+ 0 - 28
src/style/iconfont.css


+ 238 - 17
src/style/index.scss

@@ -1,4 +1,4 @@
-// @import './iconfont.css';
+@import '@/static/iconfont/iconfont.css';
 
 .test {
   // 可以通过 @apply 多个样式封装整体样式
@@ -11,14 +11,14 @@
 :root,
 page {
   font-size: 32rpx;
-  background-color: #f1f1f1;
+  background-color: #ffffff;
 
   // 修改主题色
   // --wot-color-theme: #FF8D1A;
-  --wot-color-theme: #1487f4;
-  --wot-color-success: #34d19d;
-  --wot-color-waring: #f0883a;
-  --wot-color-danger: #fa4350;
+  --wot-color-theme: #0F5FFE;
+  --wot-color-success: #05C160;
+  --wot-color-waring: #FF8D1A;
+  --wot-color-danger: #CC463D;
   --wot-color-info: #909399;
 
   // 修改按钮背景色
@@ -81,12 +81,13 @@ page {
 
 .page-list {
   min-height: 100vh;
-  background-color: white;
+  background-color: #fff;
 }
 
 .page-form {
   min-height: calc(100vh - 168rpx);
-  padding: 24rpx 24rpx 144rpx;
+  padding: 20rpx 20rpx 144rpx;
+  background-color: #f1f1f1;
 
   .form-title {
     display: flex;
@@ -110,7 +111,7 @@ page {
     position: fixed;
     bottom: 20rpx;
     z-index: 10;
-    width: calc(100vw - 48rpx);
+    width: calc(100vw - 40rpx);
   }
 
   .form-title:first-of-type {
@@ -169,7 +170,6 @@ page {
 .flex-2 {
   flex: 2 1 0%;
 }
-
 .fixed-top {
   position: fixed;
   top: -1px;
@@ -193,21 +193,242 @@ page {
 }
 
 .color-primary {
-  color: var(--wot-color-theme)
+  color: var(--wot-color-theme) !important;
 }
 .color-success {
-  color: var(--wot-color-success)
+  color: var(--wot-color-success) !important;
 }
 .color-waring {
-  color: var(--wot-color-waring)
+  color: var(--wot-color-waring) !important;
 }
 .color-danger {
-  color: var(--wot-color-danger)
+  color: var(--wot-color-danger) !important;
 }
 .color-info {
-  color: var(--wot-color-info)
+  color: var(--wot-color-info) !important;
+}
+.color-gray {
+  color: #666 !important;
 }
 
 .text-italic {
-  font-style: italic;
-}
+  font-style: italic !important; 
+}
+
+// 公共列表卡片样式
+.list-contain {  
+  .item-box {
+    padding: 20rpx;
+    margin-bottom: 20rpx;
+    border: 2rpx solid #999999;
+    border-radius: 20rpx;
+    background-color: rgba(153, 153, 153, 0.1);
+    .info-box {
+      display: flex;
+      align-items: flex-start;
+      .icon {
+      }
+      .info {
+        flex: 1;
+        .main-text {
+          display: flex;
+          align-items: flex-start;
+          .name {
+            flex: 1;
+            word-break: break-all;
+            color: #000;
+            font-size: 28rpx;
+            line-height: 48rpx;
+          }
+          .tag {
+            border: 2rpx solid var(--wot-color-theme);
+            border-radius: 8rpx;
+            background-color: rgba(15, 95, 254, 0.1);
+            color: var(--wot-color-theme);
+            font-size: 24rpx;
+            padding: 6rpx 12rpx;
+            margin-left: 10rpx;
+          }
+          .tag.success {
+            border-color: var(--wot-color-success);
+            color: var(--wot-color-success);
+            background-color: rgba(5, 193, 96, 0.1);
+          }
+          .tag.gray {
+            border-color: #a6a6a6; 
+            color: #A6A6A6;
+            background-color: rgba(166, 166, 166, 0.1);
+          }
+          .tag.danger {
+            border-color: var(--wot-color-danger);
+            color: var(--wot-color-danger);
+            background-color: rgba(204, 70, 61, 0.1);
+          }
+        }
+        .sub-text {
+          margin-top: 4rpx;
+          font-size: 24rpx;
+          color: #000;
+        }
+        .desc-text {
+          margin-top: 4rpx;
+          font-size: 24rpx;
+          color: #A6A6A6;
+        }
+      }
+    }
+    .opt-box {
+      margin-top: 30rpx;
+      text-align: right;
+      .opt-btn {
+        display: inline-block;
+        background-color: #fff;
+        color: #000;
+        font-size: 24rpx;
+        line-height: 32rpx;
+        padding: 8rpx 12rpx;
+        margin-left: 10rpx;
+        vertical-align: top;
+        border-radius: 8rpx;
+        .iconfont {
+          display: inline-block;
+          font-size: 32rpx;
+          vertical-align: top;
+        }
+      }
+      .opt-circle-btn {
+        display: inline-block;
+        background-color: var(--wot-color-theme);
+        color: #fff;
+        font-size: 24rpx;
+        line-height: 26rpx;
+        padding: 10rpx 30rpx;
+        margin-left: 20rpx;
+        border-radius: 26rpx;
+      }
+      .opt-circle-btn.danger {
+        background-color: var(--wot-color-danger);
+      }
+      .opt-circle-btn.waring {
+        background-color: var(--wot-color-waring);
+      }
+      .opt-circle-btn.info {
+        background-color: var(--wot-color-info);
+      }
+    }
+  }
+  .item-box.active {
+    background-color: rgba(15, 98, 254, 0.1);
+    border-color: #0F62FE;
+  }
+}
+
+// 公共步骤样式
+.guide-contain {
+  .step-contain {
+    display: flex;
+    align-items: center;
+    margin-top: 20rpx;
+
+    .step-item {
+      flex: 1;
+      background-color: rgba(15, 95, 254, 0.05);
+      border-radius: 20rpx;
+      position: relative;
+      font-size: 24rpx;
+      min-height: 240rpx;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      .tag {
+        position: absolute;
+        top: 0;
+        left: 0;
+        padding: 4rpx 8rpx;
+        background-color: var(--wot-color-theme);
+        color: #fff;
+        border-top-left-radius: 20rpx;
+        border-bottom-right-radius: 20rpx;
+      }
+      .icon {
+        .iconfont {
+          color: var(--wot-color-theme);
+          font-size: 80rpx;
+        }
+      }
+      .label {
+        position: absolute;
+        bottom: 10rpx;
+        left: 50%;
+        transform: translateX(-50%);
+        height: 40rpx;
+        color: #000;
+      }
+    }
+    .step-link {
+      width: 60rpx;
+      font-size: 28rpx;
+      font-weight: bold;
+      text-align: center;
+      color: var(--wot-color-theme);
+    }
+  }
+}
+
+// 操作提示区: 按钮, icon, tips
+.opt-contain {
+  text-align: center;
+  padding: 60rpx;
+  .icon {
+    .iconfont {
+      color: rgba(15, 98, 254, 0.3);
+      font-size: 160rpx;
+    }
+  }
+  .tips {
+    color: #999;
+    font-size: 24rpx;
+    margin-top: 50rpx;
+  }
+  .btn {
+    display: inline-block;
+    min-width: 300rpx;
+    padding: 26rpx;
+    margin-top: 50rpx;
+    color: #fff;
+    background-color: var(--wot-color-theme);
+    font-size: 36rpx;
+    border-radius: 50rpx;
+  }
+}
+
+// 公共视频区
+.video-contain {
+  .title {
+    display: flex;
+    align-items: center;
+    font-size: 32rpx;
+    .iconfont {
+      font-size: 32rpx;
+      color: var(--wot-color-theme);
+    }
+  }
+  .video {
+    margin-top: 20rpx;
+    width: 100%;
+    height: 300rpx;
+    line-height: 300rpx;
+    font-size: 40rpx;
+    text-align: center;
+    color: var(--wot-color-theme);
+    background-color: rgba(15, 95, 254, 0.2);
+    border-radius: 20rpx;
+  }
+}
+
+:deep(.form-contain) {
+  .wd-cell-group {
+    background-color: rgba(15, 95, 254, 0.02) !important;
+  }
+}

+ 3 - 4
src/types/uni-pages.d.ts

@@ -10,19 +10,18 @@ interface NavigateToOptions {
        "/pages/connect/index" |
        "/pages/login/index" |
        "/pages/personal/index" |
+       "/pages/personal/setting" |
        "/pages/print/index" |
        "/pages/print/job" |
        "/pages/print/jobDetail" |
        "/pages/print/jobForIntranet" |
        "/pages/printer/index" |
-       "/pages/test/index" |
-       "/pages/webview/index" |
-       "/pages/webview/sse";
+       "/pages/webview/index";
 }
 interface RedirectToOptions extends NavigateToOptions {}
 
 interface SwitchTabOptions {
-  url: "/pages/index/index" | "/pages/personal/index"
+  url: "/pages/index/index" | "/pages/assistant/index" | "/pages/personal/index"
 }
 
 type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;

+ 1 - 2
tsconfig.json

@@ -36,7 +36,6 @@
     "src/**/*.jsx",
     "src/**/*.vue",
     "src/**/*.json",
-    "src/utils/eventsource.js",
-    "src/utils/eventsource.min.js",
+    "src/static/iconfont/iconfont.js",
   ]
 }