xing.li 3 年之前
當前提交
25d6a385ce

+ 5 - 0
.idea/.gitignore

@@ -0,0 +1,5 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/

+ 6 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
+  </profile>
+</component>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/沪上阿姨项目—钉钉应用前端.iml" filepath="$PROJECT_DIR$/.idea/沪上阿姨项目—钉钉应用前端.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 12 - 0
.idea/沪上阿姨项目—钉钉应用前端.iml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/temp" />
+      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/tmp" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# HSAYI_DOCSECURITY_WEB_MOBILE
+
+沪上阿姨项目—钉钉应用前端

+ 22 - 0
babel.config.js

@@ -0,0 +1,22 @@
+// 获取 VUE_APP_ENV 非 NODE_ENV,测试环境依然 console
+const IS_PROD = ['production', 'prod'].includes(process.env.VUE_APP_ENV)
+const plugins = [
+  [
+    'import',
+    {
+      libraryName: 'vant',
+      libraryDirectory: 'es',
+      style: true
+    },
+    'vant'
+  ]
+]
+// 去除 console.log
+if (IS_PROD) {
+  plugins.push('transform-remove-console')
+}
+
+module.exports = {
+  presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]],
+  plugins
+}

文件差異過大導致無法顯示
+ 27153 - 0
package-lock.json


+ 52 - 0
package.json

@@ -0,0 +1,52 @@
+{
+  "name": "project",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "alloyfinger": "^0.1.16",
+    "axios": "^0.21.1",
+    "babel-plugin-import": "^1.13.3",
+    "core-js": "^3.6.5",
+    "dingtalk-jsapi": "^2.13.53",
+    "file-loader": "^4.2.0",
+    "less": "^3.12.2",
+    "less-loader": "^7.0.0",
+    "pdfjs-dist": "^2.0.943",
+    "vant": "^2.12.39",
+    "vue": "^2.6.11",
+    "vue-router": "^3.4.3"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "^4.5.0",
+    "@vue/cli-plugin-eslint": "^4.5.0",
+    "@vue/cli-service": "^4.5.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

二進制
public/favicon.png


+ 44 - 0
public/index.html

@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+  <link rel="icon" href="<%= BASE_URL %>favicon.png">
+
+  <!-- <% for (var i in
+      htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
+      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
+      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
+	  <% } %> -->
+  <title>
+    <%= webpackConfig.name %>
+  </title>
+  <meta name="wpk-bid" content="dta_1_1346547602">
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it
+        to continue.</strong>
+  </noscript>
+  <div id="app"></div>
+
+  <script>
+    !(function (c, i, e, b) {
+      var h = i.createElement("script");
+      var f = i.getElementsByTagName("script")[0];
+      h.type = "text/javascript";
+      h.crossorigin = true;
+      h.onload = function () {
+        c[b] || (c[b] = new c.wpkReporter({ bid: "dta_1_1346547602" }));
+        c[b].installAll()
+      };
+      f.parentNode.insertBefore(h, f);
+      h.src = e
+    })(window, document, "https://g.alicdn.com/woodpeckerx/jssdk??wpkReporter.js", "__wpk");
+  </script>
+</body>
+
+</html>

+ 24 - 0
src/App.vue

@@ -0,0 +1,24 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+ <!-- 移动端输出错误 -->
+
+<script>
+export default {
+  name: 'App'
+}
+</script>
+<style lang="less">
+html,
+body {
+  margin: 0;
+  padding: 0;
+  width: 100%;
+  height: 100%;
+  font-family: PingFang SC;
+  color: #232323;
+  background-color: #f6f6f6;
+}
+</style>

+ 9 - 0
src/api/api.js

@@ -0,0 +1,9 @@
+/*
+ * 接口统一集成模块
+ */
+import * as user from "./user";
+
+// 默认全部导出
+export default {
+  user, //登录 
+};

+ 19 - 0
src/api/index.js

@@ -0,0 +1,19 @@
+// 导入所有接口
+import api from './api'
+
+const httpApi = Vue => {
+ 
+    if (httpApi.installed)
+        return
+    httpApi.installed = true
+    Object.defineProperties(Vue.prototype, {
+        // 注意,此处挂载在 Vue 原型的 $api 对象上
+        $api: {
+            get () {
+                return api
+            }
+        }
+    })
+}
+
+export default httpApi

+ 40 - 0
src/api/user.js

@@ -0,0 +1,40 @@
+import request from '@/utils/request'
+
+//用户授权相关 
+// 获取调用钉钉api配置参数
+export const authconfig = (params) => {
+  return request({
+    url: '/api/auth/config',
+    method: 'POST',
+    params
+  })
+}
+
+// 用户信息 Parameters
+export const userinfo = (params) => {
+  return request({
+    url: '/api/user/info',
+    method: 'POST',
+    params
+  })
+}
+
+// 文件管理  
+// 获取文件详情
+export const getDetail = (id,userid) => {
+  return request({
+    url: '/api/doc/getDetail?id='+id+'&userNo='+userid,
+    method: 'GET', 
+  })
+}
+
+// 获取文件列表信息 
+export const getDocList = (data) => {
+  return request({
+    url: '/api/doc/getDocList',
+    method: 'POST',
+    data,
+    hideloading: true
+  })
+}
+

+ 112 - 0
src/assets/css/index.less

@@ -0,0 +1,112 @@
+.mainGrid {
+  margin: auto 10px;
+  padding: 10px 0px;
+  color: #232323;
+  font-size: 13px;
+  background-color: #fff;
+  border-radius: 10px;
+  // box-shadow: 0px 2px 31px 0px rgba(24, 27, 80, 0.15);
+}
+
+//三列九宫格
+.mainGridItem {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+
+  .mainGridItems {
+    position: relative;
+    width: 33%;
+
+    &.two {
+      width: 50%;
+    }
+
+    &.four {
+      width: 25%;
+    }
+
+    .mainGridItems-title {
+      text-align: center;
+      padding-top: 10px;
+      padding-bottom: 10px;
+      font-size: 13px;
+    }
+
+    .mainGridItems-img {
+      width: 100%;
+      vertical-align: middle;
+      text-align: center;
+      padding-top: 10px;
+      align-items: center;
+
+      img {
+        display: block;
+        width: 35px;
+        height: 35px;
+      }
+    }
+  }
+}
+
+//右边图片左边文字
+.iconbutton {
+  border-top: 0.5px solid #e7e7e7 !important;
+  text-align: center;
+  background: #fff;
+
+  .icon {
+    top: 2px;
+    font-size: 15px;
+    position: relative;
+    border: none;
+    color: #5c77ff;
+    background: #fff;
+  }
+
+  .btn-font {
+    color: #5c77ff;
+    font-size: 14px;
+    position: relative;
+    top: -2px;
+  }
+}
+
+.bottomButton {
+  margin: 0 auto;
+  padding-left: 10px;
+  padding-right: 10px;
+  bottom: 10px;
+  position: fixed;
+  width: 95%;
+
+  button {
+    background: #328dff;
+    border: 1px solid #328dff;
+    border-radius: 5px;
+    line-height: 50px;
+    height: 50px;
+  }
+}
+
+//列表
+.listmargin {
+  margin: 10px 0px;
+}
+
+//列表
+.listMargin2 {
+  margin: 10px 10px;
+}
+
+.app-container {
+  padding-bottom: 50px;
+}
+
+.loading {
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}

+ 14 - 0
src/assets/img/fd.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<path d="M61.076,56.816l-10.4-10.404c3.885-4.836,5.998-10.854,5.992-17.056C56.67,14.259,44.434,2.018,29.336,2.016
+	C14.239,2.014,1.998,14.251,1.996,29.348C1.994,44.445,14.231,56.686,29.328,56.688c0.002,0,0.005,0,0.008,0
+	c6.225,0.008,12.262-2.121,17.104-6.031l10.396,10.396c1.165,1.203,3.084,1.233,4.287,0.068c0.004-0.004,0.009-0.008,0.014-0.013
+	C62.302,59.905,62.275,57.986,61.076,56.816z M8.004,29.36C8,17.579,17.548,8.025,29.33,8.021
+	c11.782-0.003,21.334,9.544,21.338,21.326c0,0.004,0,0.009,0,0.013c0,11.783-9.552,21.333-21.334,21.333S8,41.143,8,29.36H8.004z
+	 M39.221,26.728h-7.253v-7.244c0-1.492-1.18-2.708-2.632-2.708s-2.632,1.216-2.632,2.708v7.248h-7.248
+	c-1.475-0.018-2.686,1.161-2.708,2.636c0,1.456,1.216,2.628,2.708,2.628h7.248v7.248c0,1.492,1.18,2.712,2.632,2.712
+	s2.632-1.22,2.632-2.712v-7.248h7.248c1.474,0.018,2.685-1.159,2.708-2.632C41.904,27.89,40.694,26.71,39.221,26.728z"/>
+</svg>

文件差異過大導致無法顯示
+ 1 - 0
src/assets/img/loading.svg


+ 8 - 0
src/assets/img/next.svg

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<path d="M32,4C16.55,4,4,16.55,4,32s12.55,28,28,28s28-12.55,28-28S47.45,4,32,4z M24.9,49l-2.85-2.85L36.25,32L22.1,17.85L24.95,15
+	l17,17L24.9,49z"/>
+</svg>

文件差異過大導致無法顯示
+ 1 - 0
src/assets/img/pre.svg


+ 13 - 0
src/assets/img/sx.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<path d="M61.076,56.816l-10.4-10.404c3.885-4.836,5.998-10.854,5.992-17.056C56.67,14.259,44.434,2.018,29.336,2.016
+	C14.239,2.014,1.998,14.251,1.996,29.348C1.994,44.445,14.231,56.686,29.328,56.688c0.002,0,0.005,0,0.008,0
+	c6.225,0.008,12.262-2.121,17.104-6.031l10.396,10.396c1.165,1.203,3.084,1.233,4.287,0.068c0.004-0.004,0.009-0.008,0.014-0.013
+	C62.302,59.905,62.275,57.986,61.076,56.816z M8.004,29.36C8,17.579,17.548,8.025,29.33,8.021
+	c11.782-0.003,21.334,9.544,21.338,21.326c0,0.004,0,0.009,0,0.013c0,11.783-9.552,21.333-21.334,21.333S8,41.143,8,29.36H8.004z
+	 M39.221,26.728H19.456c-1.475-0.018-2.686,1.161-2.708,2.636c0,1.456,1.216,2.632,2.708,2.632h19.76
+	c1.473,0.016,2.683-1.16,2.708-2.632C41.9,27.892,40.692,26.715,39.221,26.728z"/>
+</svg>

+ 44 - 0
src/components/Loading.vue

@@ -0,0 +1,44 @@
+<template>
+    <div class="loading" v-if="loading">
+        <div class="loading-mean">
+            <img src="../assets/img/loading.svg" alt="">
+            <p>loading...</p>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    props:['loading']
+}
+</script>
+
+<style>
+    .loading{
+        position:fixed;
+        top:0;
+        left:0;
+        right:0;
+        bottom:0;
+        width:100%;
+        height:100%;
+        background:rgba(0, 0, 0, 0);
+    }
+    .loading .loading-mean{
+        width:50px;
+        height:50px;
+        position:absolute;
+        top:50%;
+        left:50%;
+        transform: translate(-50%,-50%);
+    }
+    .loading .loading-mean img{
+        width:50px;
+        height:50px;
+    }
+    .loading .loading-mean p{
+        font-size:13px;
+        color:#1989fa;
+    }
+</style>
+

+ 3 - 0
src/components/bus.js

@@ -0,0 +1,3 @@
+import Vue from 'vue';
+const Bus = new Vue();
+export default Bus;

+ 6 - 0
src/config/env.development.js

@@ -0,0 +1,6 @@
+// 本地环境配置
+module.exports = {
+    title: '沪上阿姨',
+    baseApi: 'http://192.168.1.202:8083', // 本地api请求地址,注意:如果你使用了代理,请设置成'/'
+    // baseApi: 'http://192.168.3.110:8083/'
+}

+ 6 - 0
src/config/env.production.js

@@ -0,0 +1,6 @@
+// 正式
+module.exports = {
+    title: '沪上阿姨',
+    baseApi: 'http://safe-api.hsay.com:19050/', // 正式api请求地址
+    // http://safe-dd.hsay.com:19050/h5/#/index?typeId=1458721362973667329&showmenu=false&dd_orientation=landscape
+}

+ 5 - 0
src/config/index.js

@@ -0,0 +1,5 @@
+//根据环境引入不同配置 process.env.NODE_ENV
+const environment = process.env.NODE_ENV || 'development'
+console.log(process.env.NODE_ENV)
+const config = require('./env.' + environment)
+module.exports = config

+ 29 - 0
src/main.js

@@ -0,0 +1,29 @@
+// 兼容 IE
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import httpApi from './api'
+import pubFun from '../src/utils/pubFun.js'
+Vue.prototype.$pubFun = pubFun
+    // 引入全局样式
+import '@/assets/css/index.less'
+// 全局引入按需引入UI库 vant
+import '@/plugins/vant'
+
+Vue.config.productionTip = false
+Vue.use(httpApi);
+new Vue({
+    el: '#app',
+    router,
+    render: h => h(App)
+})
+
+// router.beforeEach((to, from, next) => {
+//   // 用于设置 浏览器的 title 显示
+//   if (to.meta.title) {
+//     document.title = `${to.meta.title}`
+//   } else {
+//     document.title = ''
+//   }
+//   next()
+// })

+ 36 - 0
src/plugins/vant.js

@@ -0,0 +1,36 @@
+// 按需全局引入 vant组件
+import Vue from 'vue'
+
+import {
+  Empty,
+  List,
+  Toast,
+  Field,
+  Popup,
+  Cell,
+  Icon, Button,
+  Loading, PullRefresh
+} from 'vant'
+
+
+Vue.use(Cell);
+Vue.use(Popup);
+Vue.use(Empty);
+Vue.use(List);
+Vue.use(Button);
+Vue.use(PullRefresh);
+Vue.use(Toast);
+Vue.use(Field);
+Vue.use(Icon);
+Vue.use(Loading);
+import {
+  Image as VanImage
+} from 'vant';
+
+Vue.use(VanImage);
+
+
+import { Col, Row } from 'vant';
+
+Vue.use(Col);
+Vue.use(Row);

+ 25 - 0
src/router/index.js

@@ -0,0 +1,25 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import { constantRouterMap } from './router.config.js'
+// 解决vue router 升级到3.1.x 后,重复点击导航时NavigationDuplicated
+// const originalPush = Router.prototype.push
+// Router.prototype.push = function push (location, onResolve, onReject) {
+//   if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
+//   return originalPush.call(this, location).catch(err => err)
+// }
+
+Vue.use(Router)
+
+const createRouter = () =>
+  new Router({
+    // mode: 'history', // 如果你是 history模式 需要配置vue.config.js publicPath
+    // base: process.env.BASE_URL,
+    // base: '/home/nginx/www/hsay/h5',
+    scrollBehavior: () => ({ y: 0 }),
+    routes: constantRouterMap
+  })
+
+const router = createRouter()
+console.log(router)
+export default router
+

+ 47 - 0
src/router/router.config.js

@@ -0,0 +1,47 @@
+/**
+ * 基础路由
+ * @type { *[] }
+ */
+export const constantRouterMap = [
+    {
+      path: '/',
+      name: 'home',
+      component: () => import('@/views/Index/index'),
+      meta: {
+        title: '沪上阿姨',
+        keepAlive: false
+      },
+    },
+    {
+        path: '/index',
+        name: 'index',
+        component: () =>
+            import ('@/views/list/index.vue'),
+        meta: {
+            title: '沪上阿姨',
+            keepAlive: false
+        },
+    },
+    {
+        path: '/page',
+        name: 'page',
+        component: () =>
+            import ('@/views/multiPage/index.vue'),
+        meta: {
+            title: '沪上阿姨',
+            keepAlive: false
+        },
+    },
+
+    // {
+    //   path: '/pdf',
+    //   name: 'pdf',
+    //   component: () => import('@/views/list/pdf'),
+    //   meta: {
+    //     title: '沪上阿姨',
+    //     keepAlive: false
+    //   },
+    // },
+
+
+]

+ 110 - 0
src/utils/index.js

@@ -0,0 +1,110 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * Parse the time to string
+ * @param {(Object|string|number)} time
+ * @param {string} cFormat
+ * @returns {string}
+ */
+export function parseTime(time, cFormat) {
+  if (arguments.length === 0) {
+    return null
+  }
+  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+      time = parseInt(time)
+    }
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+  if (('' + time).length === 10) {
+    time = parseInt(time) * 1000
+  } else {
+    time = +time
+  }
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '刚刚'
+  } else if (diff < 3600) {
+    // less 1 hour
+    return Math.ceil(diff / 60) + '分钟前'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '小时前'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1天前'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return (
+      d.getMonth() +
+      1 +
+      '月' +
+      d.getDate() +
+      '日' +
+      d.getHours() +
+      '时' +
+      d.getMinutes() +
+      '分'
+    )
+  }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+  const search = url.split('?')[1]
+  if (!search) {
+    return {}
+  }
+  return JSON.parse(
+    '{"' +
+      decodeURIComponent(search)
+        .replace(/"/g, '\\"')
+        .replace(/&/g, '","')
+        .replace(/=/g, '":"')
+        .replace(/\+/g, ' ') +
+      '"}'
+  )
+}

+ 40 - 0
src/utils/pubFun.js

@@ -0,0 +1,40 @@
+const pubFun = {
+  // 获取当前日期
+  date(){
+    let date = new Date();
+    let year = date.getFullYear();
+    let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth()+1) : date.getMonth() + 1;
+    let strDate = date.getDate() < 10 ? "0"+date.getDate() : date.getDate();
+    let h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
+    let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
+    let s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
+
+    return year + '-' + month + '-' + strDate + ' ' + h +':'+ m + ':'+ s
+  },
+  parseQueryString(url) {
+    var reg_url = /^[^\?]+\?([\w\W]+)$/,
+        reg_para = /([^&=]+)=([\w\W]*?)(&|$)/g, //g is very important
+        arr_url = reg_url.exec(url),
+        ret = {};
+    if (arr_url && arr_url[1]) {
+      var str_para = arr_url[1], result;
+      while ((result = reg_para.exec(str_para)) != null) {
+          ret[result[1]] = result[2];
+      }
+    }
+    return ret;
+  },
+  // 解决收起键盘后,页面上移没有归位
+  resetScrollTop(){
+    let u = navigator.userAgent, app = navigator.appVersion;
+    let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
+    if(isIOS){
+      setTimeout(() => {
+        const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop || 0
+        window.scrollTo(0, Math.max(scrollHeight - 1, 0))
+        }, 200)
+    }
+  }
+};
+
+export default pubFun;

+ 59 - 0
src/utils/request.js

@@ -0,0 +1,59 @@
+import axios from 'axios'
+import { Toast } from 'vant'
+// 根据环境不同引入不同api地址
+import { baseApi } from '@/config'
+// create an axios instance
+const service = axios.create({
+        baseURL: baseApi, // url = base api url + request url
+        withCredentials: true, // send cookies when cross-domain requests
+        timeout: 10000 // request timeout
+    })
+    //.
+    // request拦截器 request interceptor
+service.interceptors.request.use(
+        config => {
+            // 不传递默认开启loading
+            if (!config.hideloading) {
+                // loading
+                // Toast.loading({
+                //   message: '加载中...',
+                //   forbidClick: true,
+                //   loadingType: 'spinner',
+                // })
+            }
+            config.headers['X-Token'] = localStorage.getItem('hsayi-token') || '';
+            return config
+        },
+        error => {
+            // do something with request error
+            console.log(error) // for debug
+            return Promise.reject(error)
+        }
+    )
+    // respone拦截器
+service.interceptors.response.use(
+    response => {
+        Toast.clear()
+        const res = response.data;
+        if (res.code === 401) {
+            localStorage.removeItem('hsayi-token')
+                // location.reload()
+            Toast(res.message)
+            return Promise.reject(res.message);
+        }
+        if (res.code === 0 || response.request.responseType == 'blob' || res.code === 1000) {
+            return response;
+        } else {
+            Toast(res.message)
+        }
+        return Promise.reject(res.message);
+    },
+    error => {
+        Toast.clear()
+        console.log('err' + error) // for debug
+        Toast(error.message)
+        return Promise.reject(error)
+    }
+)
+
+export default service

+ 15 - 0
src/views/Index/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>沪上阿姨
+    <!-- <router-link to="/page">沪上阿姨</router-link> -->
+  </div>
+</template>
+
+<script>
+  export default {
+
+  }
+</script>
+
+<style>
+
+</style>

+ 78 - 0
src/views/list/index.less

@@ -0,0 +1,78 @@
+.layoutsMain { 
+  height: 100vh;
+  box-sizing: border-box; 
+  padding: 10px;
+  background: #f7f7f7;
+
+  .item-box {
+    background: #fff;
+    display: flex; 
+    margin-bottom: 10px;
+    padding: 10px;
+    border-radius: 10px;
+
+    .remind {
+      width: 48px;
+      height: 48px;
+      border-radius: 10px;
+      box-sizing: border-box;
+    }
+
+    .detail {
+      flex: 1;
+      margin-left: 20px;
+      .notice-header {
+        display: flex;
+        justify-content: space-between;
+        padding-bottom: 5px;
+        .notice-title {
+          font-size: 16px;
+          color: #333;
+          font-weight: bold; 
+
+          max-width: 190px;
+          word-break: break-all;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          -webkit-box-orient: vertical;
+          overflow: hidden;
+        }
+        .notice-content {
+          font-size: 12px;
+          color: #afafaf;
+          padding: 5px 0;
+        }
+      }
+    }
+
+    .line {
+      width: 0px;
+      height: 52px;
+      border: 1px solid #f58634;
+      opacity: 0.3;
+      margin-right: 10px;
+    }
+
+    .arrow {
+      font-size: 12px;
+      border-radius: 10px;
+      box-sizing: border-box;
+      margin-top: 17px;
+      color: #f58634;
+      .imgview {
+        box-sizing: border-box;
+        width: 12px;
+      }
+    }
+  }
+
+  .jurisdiction { 
+    margin: 10px; 
+    margin-top: 10vh;
+    text-align: center; 
+    font-size: 17px; 
+    color: #17a8ff;
+    opacity: 1;
+  }
+
+}

+ 245 - 0
src/views/list/index.vue

@@ -0,0 +1,245 @@
+<template>
+  <div class="layoutsMain">
+
+    <Loading :loading="!pageLoading" />
+
+    <div v-show="pageLoading">
+      <div v-show="vshowList">
+        <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+          <van-list v-model="loading" :finished="finished" @load="onLoad">
+            <div v-for="item in list" :key="item.id" :title="item" class="item-box" @click="goView(item)">
+              <div class="remind">
+                <van-image :src="require('../../../static/images/icon_pdf.png')" />
+              </div>
+              <div class="detail">
+                <div class="notice-header">
+                  <div class="notice-title">{{ item.name }}</div>
+                </div>
+                <div class="notice-content">
+                  {{ item.fileSize}}
+                </div>
+              </div>
+
+              <div class="line"></div>
+              <div class="arrow">
+                <van-image class="imgview" :src="require('../../../static/images/icon_view.png')" />
+                查看
+              </div>
+            </div>
+          </van-list>
+        </van-pull-refresh>
+        <van-empty v-if="list.length == 0" description="暂无数据" />
+      </div>
+
+      <div v-show="!vshowList" class="jurisdiction">
+        <van-image :src="require('../../../static/images/icon_jurisdiction.png')" />
+        <div>{{nomessage}}</div>
+      </div>
+
+    </div>
+
+  </div>
+</template>
+
+<script>
+  import Loading from '@/components/Loading';
+
+  import * as dd from 'dingtalk-jsapi';
+  export default {
+    data() {
+      return {
+        list: [],
+        pageLoading: false,
+        vshowList: true,
+        loading: false,
+        finished: false,
+        refreshing: false,
+        nomessage: '暂无访问权限',
+        pageInfo: {
+          pageIndex: 1,
+          pageSize: 10
+        },
+      }
+    },
+    components: {
+      Loading
+    },
+    created() {
+      this.getAuthconfig();
+    },
+    methods: {
+      goView(item) {
+        this.$router.push({
+          name: 'page',
+          query: {
+            id: item.id,
+            title: item.name
+          }
+        })
+      },
+      onLoad() {
+
+        let self = this
+        //判断获取到分类id
+        if (this.$route.query.typeId) {
+          if (this.refreshing) {
+            this.list = []
+            this.refreshing = false
+            this.pageInfo.pageIndex = 1
+          }
+
+          const params = {
+            typeId: this.$route.query.typeId || '',
+            page: this.pageInfo.pageIndex,
+            pageSize: this.pageInfo.pageSize
+          }
+          this.$api.user.getDocList(params).then((response) => {
+            self.pageLoading = true;
+
+            const res = response.data;
+
+            if (res.code == 0 && res.data.list) {
+              if (res.data.list.length == 1 && this.pageInfo.pageIndex == 1) {
+                self.loading = false
+                self.finished = true
+                let item = res.data.list[0];
+                this.$router.replace({
+                  name: 'page',
+                  query: {
+                    id: item.id,
+                    title: item.name
+                  }
+                })
+              } else {
+                self.list.push(...res.data.list)
+                self.pageInfo.pageIndex += 1
+                self.loading = false
+                if (self.list.length >= res.data.totalCount) {
+                  self.finished = true
+                }
+                this.ChangePageTitle(self.list[0].typeName)
+              }
+            } else if (res.code == 1000) { //没有查看权限
+              this.vshowList = false;
+              this.nomessage = res.message
+            }
+          }).catch(err => {
+            console.log(err);
+            self.pageLoading = true;
+          });
+        } else if (this.$route.query.docId) { //直接获取到分件Id 打开文件, title: '阅读'  
+          this.$api.user.getDetail(this.$route.query.docId, localStorage.userId || '').then((response) => {
+            self.pageLoading = true;
+            const res = response.data.data;
+            if (res.code == 0 && res.data) {
+              let path = res.data.path || ''
+              this.$router.replace({
+                name: 'page',
+                query: {
+                  path: path,
+                  title: res.data.fileName
+                }
+              })
+            } else if (res.code == 1000) { //没有查看权限
+              this.vshowList = false;
+              this.nomessage = res.message
+            }
+          }).catch(err => {
+            console.log(err);
+            self.pageLoading = true;
+          });
+        }
+      },
+      onRefresh() {
+        // 清空列表数据
+        this.finished = false
+        // 重新加载数据
+        // 将 loading 设置为 true,表示处于加载状态
+        this.loading = true
+        this.onLoad()
+      },
+      //钉钉授权
+      getAuthconfig() {
+
+        this.$api.user.authconfig({
+          url: location.origin + '/'
+        }).then((response) => {
+          if (response.data.code == 0) {
+            if (dd.env.platform != 'notInDingTalk') {
+              //该方法必须带上,用来捕获鉴权出现的异常信息,否则不方便排查出现的问题
+              dd.ready(() => {
+                dd.runtime.permission.requestAuthCode({
+                  corpId: response.data.data.corpId, // 企业id
+                  onSuccess: (info) => {
+                    localStorage.setItem('hsayi-token', info.code);
+                    this.getUserInfo();
+                  },
+                  onFail: function (err) {
+                    console.log(err);
+                    this.pageLoading = true;
+                    this.vshowList = false;
+                    alert('dd error: ' + JSON.stringify(err));
+                  }
+                });
+              });
+
+              dd.biz.navigation.setRight({
+                show: false, //控制按钮显示, true 显示, false 隐藏, 默认true
+                control: false, //是否控制点击事件,true 控制,false 不控制, 默认false
+                showIcon: false, //是否显示icon,true 显示, false 不显示,默认true; 注:具体UI以客户端为准
+                onSuccess: () => {},
+                onFail: function (err) {
+                  console.log(err);
+                  alert('dd error: ' + JSON.stringify(err));
+                }
+              });
+
+            } else {
+              //本地调试不在钉钉上
+              this.vshowList = false;
+              localStorage.setItem('hsayi-token', '5c976f38445339f6b302390a61653b69');
+              this.getUserInfo();
+            }
+          }
+        }).catch(err => {
+          console.log(err);
+          this.pageLoading = true;
+        });
+      },
+      // 获取用户信息
+      getUserInfo() {
+        this.$api.user.userinfo().then((res) => {
+          if (res.data.code == 0) {
+            localStorage.setItem('userId', res.data.data.userId);
+            this.vshowList = true;
+            this.onLoad();
+          }
+        }).catch(err => {
+          console.log(err);
+          this.pageLoading = true;
+        });
+      },
+      ChangePageTitle(title) {
+        if (dd.env.platform != 'notInDingTalk') {
+          dd.ready(function () {
+            dd.biz.navigation.setTitle({
+              title: title, //控制标题文本,空字符串表示显示默认文本
+              onSuccess: function (result) {
+                console.log(result);
+              },
+              onFail: function (err) {
+                console.log(err);
+              }
+            });
+          });
+        } else {
+          document.title = title
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  @import "index.less";
+</style>

+ 153 - 0
src/views/list/pdf.vue

@@ -0,0 +1,153 @@
+<template>
+  <div class="cpdf" id="cpdf">
+    <Loading :loading="loading" />
+    <canvas v-for="item in numPages" :key="item" :id="'pdf'+item" />
+  </div>
+</template>
+
+<script>
+  import * as dd from 'dingtalk-jsapi';
+  import Loading from '@/components/Loading';
+  import pdfjsLib from 'pdfjs-dist';
+  export default {
+    components: {
+      // pdfjsLib,
+      Loading
+    },
+    data() {
+      return {
+        numPages: 0,
+        pdfSrc: '', // pdf文件地址
+        loading: true
+      }
+    },
+    created() {
+
+      if (this.$route.query.path) {
+        this.loadPdfHandler(this.$route.query.path);
+      }
+
+      if (this.$route.query.title) {
+        this.ChangePageTitle(this.$route.query.title)
+      }
+
+      if (this.$route.query.id) {
+        this.getDetail();
+      } else {
+        this.loading = false;
+        // let path = 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf'//你的pdf地址
+        // this.loadPdfHandler(path);
+      }
+      // if (dd.env.platform != 'notInDingTalk') {
+      //   dd.biz.util.share({
+      //     type: 2,//分享类型,0:全部组件 默认;1:只能分享到钉钉;2:不能分享,只有刷新按钮
+      //     url: '',
+      //     title: '',
+      //     content: '',
+      //     image: null,
+      //     onSuccess: function () {
+      //       //onSuccess将在调起分享组件成功之后回调
+      //       /**/
+      //     },
+      //     onFail: function (err) { }
+      //   })
+      // }
+    },
+    methods: {
+      // pdf加载时
+      loadPdfHandler(path) {
+        try {
+          let loadingTask = pdfjsLib.getDocument({
+            url: path,
+            // cMapUrl: "https://unpkg.com/browse/pdfjs-dist@2.2.228/cmaps/",
+            // cMapUrl:"../../assets/cmaps/",
+            // cMapPacked: true
+          });
+
+          let _this = this;
+
+          loadingTask.promise.then((pdf) => {
+            this.numPages = pdf.numPages;
+            for (let i = 1; i <= pdf.numPages; i++) {
+              pdf.getPage(i).then(function (page) {
+                var scale = 5; //缩放比例
+                var viewport = page.getViewport(scale);
+                var canvas = document.getElementById('pdf' + i);
+                var context = canvas.getContext('2d');
+                canvas.height = viewport.height;
+                canvas.width = viewport.width;
+                canvas.style.width = '100%';
+                var renderContext = {
+                  canvasContext: context,
+                  viewport: viewport
+                };
+
+                page.render(renderContext);
+              });
+            }
+            _this.loading = false;
+
+          }).catch(() => {
+
+            _this.loading = false;
+          });
+
+        } catch (e) {
+          // 错误处理代码片段
+          this.loading = false;
+        }
+      },
+      getDetail() {
+        let self = this;
+        this.$api.user.getDetail(this.$route.query.id, localStorage.userId || '').then((response) => {
+          const res = response.data.data;
+          let path = res.data.path || ''
+          self.loadPdfHandler(path);
+          self.ChangePageTitle(res.data.fileName);
+        }).catch(() => {
+          self.loading = false;
+        });
+      },
+      ChangePageTitle(title) {
+        if (dd.env.platform != 'notInDingTalk') {
+          dd.ready(function () {
+            dd.biz.navigation.setTitle({
+              title: title, //控制标题文本,空字符串表示显示默认文本
+              onSuccess: function () {},
+              onFail: function () {}
+            });
+          });
+        } else {
+          document.title = title
+        }
+      },
+    }
+  }
+</script>
+<style lang="less" scoped>
+  .cpdf {
+    width: 100%;
+    height: 100%;
+    margin: 0 auto;
+    overflow-x: hidden;
+    overflow-y: auto;
+
+    .center {
+      height: 100%;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .contor {
+      display: flex;
+      justify-content: center;
+      margin: 20px;
+      padding: 10px;
+
+      .bottom {
+        font-size: 15px;
+        padding-top: 5px;
+      }
+    }
+  }
+</style>

+ 95 - 0
src/views/multiPage/bar.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="bar" v-show="showbar">
+
+    <span><img src="../../assets/img/pre.svg" @click="prePage" /></span>
+    <div class="itemTime">
+      <input class="barinputL" type="number" id="spinner_amount" :value="curPage" @blur="chagePage"
+        oninput="value=value.replace(/[^\d]/g,'')" />
+      <div class="barinputR">/{{ total }}</div>
+
+    </div>
+
+    <span><img src="../../assets/img/next.svg" @click="nextPage" /></span>
+  </div>
+</template>
+
+<script>
+  import Bus from '@/components/bus';
+  export default {
+    data() {
+      return {
+        total: 0,
+        showbar: false,
+      }
+    },
+    props: ['curPage', 'prePage', 'nextPage', 'bigPage', 'smallPage'],
+    mounted() {
+      Bus.$on("total", val => {
+        this.total = val;
+      })
+    },
+    methods: {
+      chagePage() {
+        this.$pubFun.resetScrollTop();
+        let spinner = document.getElementById('spinner_amount');
+        let val = spinner.valueAsNumber
+
+        if (val) {
+
+          if (this.total < val) {
+            val = this.total
+            spinner.valueAsNumber = this.total
+          }
+
+          this.$emit('jumpPage', val);
+        } else {
+          spinner.valueAsNumber = this.curPage
+        }
+
+      }
+
+    }
+  }
+</script>
+
+<style lang='less' scoped>
+  .bar {
+    position: fixed;
+    bottom: 10px;
+    left: 0;
+    right: 0;
+    height: 50px;
+    width: 100%;
+    display: flex;
+    z-index: 99 !important;
+  }
+
+  .bar span {
+    flex: 1;
+    text-align: center;
+    height: 50px;
+  }
+
+  .bar span img {
+    width: 35px;
+    margin-top: 8px;
+  }
+
+  .barinputL {
+    margin-top: 10px;
+    width: 40px;
+    height: 20px;
+    text-align: center;
+  }
+
+  .barinputR {
+    margin-top: 15px;
+    margin-left: 5px;
+    text-align: center;
+  }
+
+  .itemTime {
+    justify-content: space-between;
+    display: flex;
+  }
+</style>

+ 90 - 0
src/views/multiPage/canvasPage.vue

@@ -0,0 +1,90 @@
+<template>
+  <div>
+    <!-- {{scale.toFixed(1)}} -->
+    <div style="width: 10px; height:100px; background: green; position: fixed; top:0; left: 0; z-index: 30;"
+      v-for="(item, index) in testLog" :key="index">{{item}}</div>
+    <canvas id="pdf" style="background: red;" />
+  </div>
+</template>
+<script>
+  import pdfjsLib from 'pdfjs-dist';
+  import Bus from '@/components/bus';
+  export default {
+    data() {
+      return {
+        src: null,
+        numPages: 0,
+        pg: this.curPage,
+        sc: this.scale,
+        testLog: []
+      }
+    },
+    props: ['curPage', 'scale'],
+    mounted() {
+      // this.init(this.curPage, this.scale.toFixed(1));
+    },
+    watch: {
+      curPage(pg) {
+        this.pg = pg;
+        this.init(pg, this.sc);
+      },
+      scale(sc) {
+        this.sc = sc;
+        this.init(this.pg, sc);
+      }
+    },
+    methods: {
+      start() {
+        this.testLog.push("1", this.curPage, this.scale);
+        this.init(this.curPage, this.scale.toFixed(1));
+      },
+      init(pg, sc) {
+        if (!this.src) {
+          return
+        }
+        this.$emit('loadingFun', true);
+        let loadingTask = pdfjsLib.getDocument({
+          url: this.src,
+          cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.943/cmaps/",
+          cMapPacked: true
+        });
+
+        // let loadingTask = pdfjsLib.getDocument(this.src);
+        let _this = this;
+        loadingTask.promise.then((pdf) => {
+          _this.testLog.push("3", pdf.numPages, pdf.numPages, JSON.stringify(pdf));
+          Bus.$emit("total", pdf.numPages);
+          this.$emit("totals", pdf.numPages);
+
+          pdf.getPage(pg).then(function (page) {
+            let scale = Number(sc).toFixed(1);
+            let viewport = page.getViewport(scale);
+            let canvas = document.getElementById('pdf');
+            let context = canvas.getContext('2d');
+
+            canvas.height = viewport.height;
+            canvas.width = viewport.width;
+
+            let renderContext = {
+              canvasContext: context,
+              viewport: viewport
+            };
+            page.render(renderContext);
+          }).catch((err) => {
+            console.log(err)
+            _this.testLog.push("2", this.curPage, this.scale, JSON.stringify(err));
+          });
+          _this.$emit('loadingFun', false);
+        });
+      }
+    }
+  }
+</script>
+<style>
+  #pdf {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+  }
+</style>

+ 261 - 0
src/views/multiPage/index.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="page">
+    <Loading :loading="loading" />
+    <div v-show="!loading">
+      <van-image-preview v-model="vshowList" :images="detailData.imageFiles" :start-position='0' @change="onChange"
+                         @scale='onScale' @close='onClose' ref='imagePreview'>
+        <template v-slot:index>
+          <div>
+            第{{curPage}}页
+          </div>
+        </template>
+        <template v-slot:cover v-if="showBottom">
+          <div class="pdf-cover-bottom">
+            <input class="pdf-barinputL" ref='pdfInput' type="number" id="spinner_amount" :value="curPage"
+                   @input="pdfInput" />
+            <!-- oninput="" -->
+            <div class="pdf-barinputR">/{{ detailData.imageFiles.length}}</div>
+          </div>
+        </template>
+      </van-image-preview>
+      <div v-show="!vshowList" class="jurisdiction">
+        <van-image :src="require('../../../static/images/icon_jurisdiction.png')" />
+        <div>{{nomessage}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as dd from 'dingtalk-jsapi';
+import Loading from '@/components/Loading';
+import {
+  ImagePreview
+} from 'vant';
+export default {
+  name: 'page',
+  data() {
+    return {
+      nomessage: '',
+      vshowList: false,
+      pdfFile: null,
+      loading: true,
+      curPage: 1,
+      curPage2: 1,
+      totals: 0,
+      scale: 2,
+      show: true,
+      detailData: null,
+      showBottom: false,
+      timeCountId: null,
+    }
+  },
+  watch: {
+    vshowList(nval, oval) {
+      if (oval && !nval) {
+        this.vshowList = true;
+      }
+    }
+  },
+  created() {
+    if (this.$route.query.path) {
+      this.loadPdfHandler(this.$route.query.path);
+    }
+
+    if (this.$route.query.title) {
+      this.ChangePageTitle(this.$route.query.title)
+    }
+    if (this.$route.query.id) {
+      this.loading = true;
+      this.getDetail();
+    } else {
+      // this.loadPdfHandler('http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf');
+      this.loading = false;
+    }
+
+    if (dd.env.platform != 'notInDingTalk') {
+      dd.biz.navigation.setRight({
+        show: false, //控制按钮显示, true 显示, false 隐藏, 默认true
+        control: false, //是否控制点击事件,true 控制,false 不控制, 默认false
+        showIcon: false, //是否显示icon,true 显示, false 不显示,默认true; 注:具体UI以客户端为准
+        onSuccess: () => {},
+        onFail: function (err) {
+          alert('dd error: ' + JSON.stringify(err));
+        }
+      });
+
+    }
+  },
+  destroyed() {
+    this.clearTimeCount();
+  },
+  components: {
+    Loading,
+    [ImagePreview.Component.name]: ImagePreview.Component,
+  },
+  methods: {
+    // pdf加载时
+    loadPdfHandler(path) {
+      this.$nextTick(() => {
+        this.$refs.canvas.src = path
+        this.$refs.canvas.start();
+      });
+    },
+    // 获取详情
+    getDetail() {
+      let self = this;
+
+      this.$api.user.getDetail(this.$route.query.id, localStorage.userId || '').then((response) => {
+        const res = response.data.data;
+        this.loading = false;
+        if (res.code == 0 && res.data) {
+          this.detailData = res.data;
+          this.vshowList = true;
+          this.$nextTick(() => {
+            this.showBottom = true
+          })
+          // let path = res.data.path || ''
+          // self.loadPdfHandler(path);
+          // self.loadPdfHandler("http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf");
+          self.ChangePageTitle(res.data.fileName);
+        } else if (res.code == 1000) { //没有查看权限
+          this.vshowList = false;
+          this.nomessage = res.message
+        }
+      }).catch(err => {
+        console.log(err)
+        self.loading = false;
+      });
+    },
+    // 修改页面标题
+    ChangePageTitle(title) {
+      if (dd.env.platform != 'notInDingTalk') {
+        dd.ready(function () {
+          dd.biz.navigation.setTitle({
+            title: title, //控制标题文本,空字符串表示显示默认文本
+            onSuccess: function (result) {
+              console.log(result);
+            },
+            onFail: function (err) {
+              console.log(err);
+            }
+          });
+        });
+      } else {
+        document.title = title
+      }
+    },
+    // 缩放
+    onScale() {
+      document.getElementById("spinner_amount").blur();
+    },
+    // 关闭
+    onClose() {
+      document.getElementById("spinner_amount").blur();
+    },
+    // 页面切换
+    onChange(val) {
+      this.curPage = val + 1;
+      document.getElementById("spinner_amount").blur();
+    },
+    // 开始输入计时
+    startTimeCount(f) {
+      this.clearTimeCount();
+      this.timeCountId = setTimeout(() => {
+        f();
+      }, 700)
+    },
+    // 清除输入计时
+    clearTimeCount() {
+      if (this.timeCountId) {
+        clearTimeout(this.timeCountId);
+        this.timeCountId = null;
+      }
+    },
+    // 页码输入
+    pdfInput(e) {
+      let value = e.target.value;
+      if (value) {
+        value = value.replace(/[^\d]/g, '')
+      }
+      this.curPage = value;
+      this.startTimeCount(() => {
+        if (!value) {
+          this.jumpPage(0);
+        } else if (parseInt(value) > parseInt(this.detailData.imageFiles.length)) {
+          this.jumpPage(this.detailData.imageFiles.length);
+        } else {
+          this.jumpPage(value)
+        }
+      })
+    },
+    // 输入框失去焦点
+    pdfInputBlur() {
+      let spinner = document.getElementById('spinner_amount');
+      let val = spinner.valueAsNumber
+      if (val) {
+        if (this.detailData.imageFiles.length < val) {
+          val = this.detailData.imageFiles.length;
+          spinner.valueAsNumber = this.detailData.imageFiles.length;
+        }
+        this.jumpPage(val);
+      } else {
+        spinner.valueAsNumber = this.curPage
+      }
+    },
+    // 切换页面
+    jumpPage(val) {
+      console.log(val)
+      if (0 < val && val <= this.detailData.imageFiles.length) {
+        this.curPage = val;
+        this.$refs.imagePreview.swipeTo(val - 1);
+      }
+    },
+  }
+}
+</script>
+
+<style scoped>
+.jurisdiction {
+  margin: 10px;
+  margin-top: 10vh;
+  text-align: center;
+  font-size: 17px;
+  color: #17a8ff;
+  opacity: 1;
+}
+
+.pdf-cover-bottom {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: #fff;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  padding: 20px 10px;
+}
+
+.pdf-barinputL {
+  width: 40px;
+  height: 20px;
+  text-align: center;
+}
+
+.pdf-barinputR {
+  margin-left: 5px;
+  text-align: center;
+}
+
+.pdf-jump-button {
+  position: absolute;
+  top: 50%;
+  right: 30px;
+  transform: translateY(-50%);
+  border-radius: 5px;
+  background: #17a8ff;
+  color: #fff;
+}
+</style>

二進制
static/images/icon_jurisdiction.png


二進制
static/images/icon_pdf.png


二進制
static/images/icon_view.png


+ 18 - 0
vue.config.js

@@ -0,0 +1,18 @@
+module.exports = {
+  publicPath: './', // 署应用包时的基本 URL。 vue-router hash 模式使用
+  // publicPath: '/h5/', //署应用包时的基本 URL。  vue-router history模式使用
+  outputDir: 'dist', //  生产环境构建文件的目录
+  assetsDir: 'static', //  outputDir的静态资源(js、css、img、fonts)目录
+  lintOnSave: false,
+  filenameHashing: false,
+  productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
+  devServer: {
+    port: 9090, // 端口
+    open: true, // 启动后打开浏览器
+    overlay: {
+      //当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
+      warnings: false,
+      errors: true
+    } 
+  }, 
+}