diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..99057ba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+unpackage/
\ No newline at end of file
diff --git a/App.vue b/App.vue
index ee288b1..5524441 100644
--- a/App.vue
+++ b/App.vue
@@ -1,32 +1,106 @@
+ /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
+
\ No newline at end of file
diff --git a/main.js b/main.js
index cb25a2f..ca0a380 100644
--- a/main.js
+++ b/main.js
@@ -1,8 +1,7 @@
-
-// #ifndef VUE3
import Vue from 'vue'
import App from './App'
-
+import mixin from '@/utils/mixin.js'
+Vue.mixin(mixin);
Vue.config.productionTip = false
App.mpType = 'app'
@@ -11,15 +10,3 @@ const app = new Vue({
...App
})
app.$mount()
-// #endif
-
-// #ifdef VUE3
-import { createSSRApp } from 'vue'
-import App from './App.vue'
-export function createApp() {
- const app = createSSRApp(App)
- return {
- app
- }
-}
-// #endif
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index cac8ba6..b1fca20 100644
--- a/manifest.json
+++ b/manifest.json
@@ -56,5 +56,13 @@
},
"usingComponents" : true
},
- "vueVersion" : "2"
+ "vueVersion" : "2",
+ "h5" : {
+ "router" : {
+ "base" : "/h5/"
+ },
+ "devServer" : {
+ "https" : false
+ }
+ }
}
diff --git a/pages/index/index.vue b/pages/index/index.vue
index bf8e0c1..becbae7 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -1,25 +1,27 @@
-
-
+
+
-
+
+ css="width: 18%;position:absolute;bottom:20rpx;left:110rpx" />
+ {{getFormattedTime()}}
-
-
-
-
-
-
+
+
↑↑↑长按图片保存↑↑↑
+
+
+
+
@@ -40,31 +42,101 @@
diff --git a/static/img/1.jpg b/static/img/1.jpg
deleted file mode 100644
index b39f46e..0000000
Binary files a/static/img/1.jpg and /dev/null differ
diff --git a/store/$tn.mixin.js b/store/$tn.mixin.js
new file mode 100644
index 0000000..ab7689b
--- /dev/null
+++ b/store/$tn.mixin.js
@@ -0,0 +1,28 @@
+import { mapState } from 'vuex'
+import store from '@/store'
+
+// 尝试将用户在根目录中的store/index.js的vuex的state变量加载到全局变量中
+let $tStoreKey = []
+try {
+ $tStoreKey = store.state ? Object.keys(store.state) : []
+} catch(e) {
+
+}
+
+module.exports = {
+ beforeCreate() {
+ // 将vuex方法挂在在$t中
+ // 使用方法:
+ // 修改vuex的state中的user.name变量为图鸟小菜 => this.$tn.vuex('user.name', '图鸟小菜')
+ // 修改vuexde state中的version变量为1.0.1 => this.$tn.vuex('version', 1.0.1)
+ this.$tn.vuex = (name, value) => {
+ this.$store.commit('$tStore', {
+ name, value
+ })
+ }
+ },
+ computed: {
+ // 将vuex的state中的变量结构到全局混入mixin中
+ ...mapState($tStoreKey)
+ }
+}
\ No newline at end of file
diff --git a/store/index.js b/store/index.js
new file mode 100644
index 0000000..9fe6205
--- /dev/null
+++ b/store/index.js
@@ -0,0 +1,76 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+let lifeData = {}
+
+// 尝试获取本地是否存在lifeData变量,第一次启动时不存在
+try {
+ lifeData = uni.getStorageSync('lifeData')
+} catch (e) {
+
+}
+
+// 标记需要永久存储的变量,在每次启动时取出,在state中的变量名
+let saveStateKeys = ['vuex_user']
+
+// 保存变量到本地存储
+const saveLifeData = function(key, value) {
+ // 判断变量是否在存储数组中
+ if (saveStateKeys.indexOf(key) != -1) {
+ // 获取本地存储的lifeData对象,将变量添加到对象中
+ let tmpLifeData = uni.getStorageSync('lifeData')
+ // 第一次启动时不存在,则放一个空对象
+ tmpLifeData = tmpLifeData ? tmpLifeData : {},
+ tmpLifeData[key] = value
+ // 将变量再次放回本地存储中
+ uni.setStorageSync('lifeData', tmpLifeData)
+ }
+}
+
+const store = new Vuex.Store({
+ state: {
+ // 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
+ // 加上vuex_前缀,是防止变量名冲突,也让人一目了然
+ vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {
+ name: '灵睿'
+ },
+
+ // 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式
+ // app版本
+ vuex_version: "1.0.3",
+ // 是否使用自定义导航栏
+ vuex_custom_nav_bar: true,
+ // 状态栏高度
+ vuex_status_bar_height: 0,
+ // 自定义导航栏的高度
+ vuex_custom_bar_height: 0
+ },
+ mutations: {
+ $tStore(state, payload) {
+ // 判断是否多层调用,state中为对象存在的情况,例如user.info.score = 1
+ let nameArr = payload.name.split('.')
+ let saveKey = ''
+ let len = nameArr.length
+ if (len >= 2) {
+ let obj = state[nameArr[0]]
+ for (let i = 1; i < len - 1; i++) {
+ obj = obj[nameArr[i]]
+ }
+ obj[nameArr[len - 1]] = payload.value
+ saveKey = nameArr[0]
+ } else {
+ // 单层级变量
+ state[payload.name] = payload.value
+ saveKey = payload.name
+ }
+
+ // 保存变量到本地中
+ saveLifeData(saveKey, state[saveKey])
+ }
+ },
+ actions: {}
+})
+
+export default store
\ No newline at end of file
diff --git a/utils/api.js b/utils/api.js
new file mode 100644
index 0000000..79debc0
--- /dev/null
+++ b/utils/api.js
@@ -0,0 +1,3 @@
+import request from '@/utils/request';
+export const getInfo = data => request.post('/api/signature/getTkenFind', data, false);
+export const getUpdate = data => request.post('/api/signature/update', data, false);
\ No newline at end of file
diff --git a/utils/mixin.js b/utils/mixin.js
new file mode 100644
index 0000000..05a1b1c
--- /dev/null
+++ b/utils/mixin.js
@@ -0,0 +1,59 @@
+
+function v(a, b) {
+ return +((1000 * a - 1000 * b) / 1000).toFixed(1)
+}
+module.exports = {
+ created() {
+ if (this._setTransform) {
+ this._setTransform = (x, y, scale, source = '', r, o) => {
+ if (!(x !== null && x.toString() !== 'NaN' && typeof x === 'number')) {
+ x = this._translateX || 0
+ }
+ if (!(y !== null && y.toString() !== 'NaN' && typeof y === 'number')) {
+ y = this._translateY || 0
+ }
+ x = Number(x.toFixed(1))
+ y = Number(y.toFixed(1))
+ scale = Number(scale.toFixed(1))
+ if (!(this._translateX === x && this._translateY === y)) {
+ if (!r) {
+ this.$trigger('change', {}, {
+ x: v(x, this._scaleOffset.x),
+ y: v(y, this._scaleOffset.y),
+ source: source
+ })
+ }
+ }
+ if (!this.scale) {
+ scale = this._scale
+ }
+ scale = this._adjustScale(scale)
+ scale = +scale.toFixed(3)
+ if (o && scale !== this._scale) {
+ this.$trigger('scale', {}, {
+ x: x,
+ y: y,
+ scale: scale
+ })
+ }
+ var transform = 'translateX(' + x + 'px) translateY(' + y + 'px) scale(' + scale + ')'
+ this.$el.style.transform = transform
+ this.$el.style.webkitTransform = transform
+ this._translateX = x
+ this._translateY = y
+ this._scale = scale
+ }
+ }
+ },
+ destroyed() {
+ //解决预览模式关闭后,和重复开关预览模式this._setTransform函数无限次执行导致手机卡顿的问题
+ if (this._FA) {
+ this._FA.cancel()
+ }
+ if (this._SFA) {
+ this._SFA.cancel()
+ }
+ },
+ methods: {
+ }
+}
\ No newline at end of file
diff --git a/utils/request.js b/utils/request.js
new file mode 100644
index 0000000..86be710
--- /dev/null
+++ b/utils/request.js
@@ -0,0 +1,57 @@
+import {
+ toast,
+ clearStorageSync,
+ getStorageSync,
+ useRouter
+} from './utils'
+
+import RequestManager from '@/utils/requestManager.js'
+
+let BASE_URL = 'http://qz.hschool.com.cn';
+
+const baseRequest = async (url, method, data = {}, loading = true) => {
+ //const u = getStorageSync('u');
+ // let requestId = manager.generateId(method, url, data)
+ // if (!requestId) {
+ // console.log('重复请求')
+ // }
+ // if (!requestId) return false;
+ return new Promise((reslove, reject) => {
+ loading && uni.showLoading({
+ title: '加载中...'
+ })
+ uni.request({
+ url: BASE_URL + url,
+ method: method || 'GET',
+ header: {
+ 'content-type': 'application/json'
+ },
+ timeout: 10000,
+ data: data || {},
+ complete: () => {
+ uni.hideLoading()
+ },
+ success: (successData) => {
+ const res = successData.data;
+ if (successData.statusCode == 200) {
+ reslove(res)
+ } else {
+ //toast('网络连接失败,请稍后重试')
+ reject(res)
+ }
+ },
+ fail: (msg) => {
+ toast('网络连接失败,请稍后重试')
+ reject(msg)
+ }
+ })
+ })
+}
+
+const request = {};
+
+['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
+ request[method] = (api, data, loading) => baseRequest(api, method, data, loading)
+})
+
+export default request
\ No newline at end of file
diff --git a/utils/requestManager.js b/utils/requestManager.js
new file mode 100644
index 0000000..56dff20
--- /dev/null
+++ b/utils/requestManager.js
@@ -0,0 +1,66 @@
+class RequestManager {
+ constructor() {
+ this.idMap = new Map()
+ }
+ /**
+ * 生成唯一ID,并将ID和请求信息存储到map对象中
+ * @param {string} method - 请求方法
+ * @param {string} url - 请求URL
+ * @param {object} params - 请求参数
+ * @returns {string|boolean} - 生成的唯一ID,如果存在相同请求则返回false
+ */
+ generateId(method, url, params) {
+ const id = this.generateUniqueId(method, url, params)
+ if (this.idMap.has(id)) {
+ return false
+ }
+ this.idMap.set(id, { method, url, params })
+ return id
+ }
+
+ /**
+ * 根据ID删除map对象中的请求信息
+ * @param {string} id - 要删除的唯一ID
+ */
+ deleteById(id) {
+ this.idMap.delete(id)
+ }
+
+ /**
+ * 生成唯一ID的方法
+ * @param {string} method - 请求方法
+ * @param {string} url - 请求URL
+ * @param {object} params - 请求参数
+ * @returns {string} - 生成的唯一ID
+ */
+ generateUniqueId(method, url, params) {
+ const idString = `${method}-${url}-${this.serializeObject(params)}`
+ let id = 0;
+ for (let i = 0; i < idString.length; i++) {
+ id = ((id << 5) - id) + idString.charCodeAt(i)
+ id |= 0;
+ }
+ return id.toString()
+ }
+
+ /**
+ * 序列化对象为字符串
+ * @param {object} obj - 要序列化的对象
+ * @returns {string} - 序列化后的字符串
+ */
+ serializeObject(obj) {
+ const keys = Object.keys(obj).sort()
+ const serializedObj = {}
+ for (let key of keys) {
+ const value = obj[key]
+ if (value !== null && typeof value === 'object') {
+ serializedObj[key] = this.serializeObject(value)
+ } else {
+ serializedObj[key] = value
+ }
+ }
+ return JSON.stringify(serializedObj)
+ }
+}
+
+export default RequestManager
\ No newline at end of file
diff --git a/utils/utils.js b/utils/utils.js
new file mode 100644
index 0000000..7ca8ccb
--- /dev/null
+++ b/utils/utils.js
@@ -0,0 +1,136 @@
+/**
+ * 提示方法
+ * @param {String} title 提示文字
+ * @param {String} icon icon图片
+ * @param {Number} duration 提示时间
+ */
+export function toast(title, icon = 'none', duration = 1500) {
+ if(title) {
+ uni.showToast({
+ title,
+ icon,
+ duration
+ })
+ }
+}
+
+/**
+ * 设置缓存
+ * @param {String} key 键名
+ * @param {String} data 值
+ */
+export function setStorageSync(key, data) {
+ uni.setStorageSync(key, data)
+}
+
+/**
+ * 获取缓存
+ * @param {String} key 键名
+ */
+export function getStorageSync(key) {
+ return uni.getStorageSync(key)
+}
+
+/**
+ * 删除缓存
+ * @param {String} key 键名
+ */
+export function removeStorageSync(key) {
+ return uni.removeStorageSync(key)
+}
+
+/**
+ * 清空缓存
+ * @param {String} key 键名
+ */
+export function clearStorageSync() {
+ return uni.clearStorageSync()
+}
+
+
+/**
+ * 页面跳转
+ * @param {'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab' | 'navigateBack' | number } url 转跳路径
+ * @param {String} params 跳转时携带的参数
+ * @param {String} type 转跳方式
+ **/
+export function useRouter(url, params = {}, type = 'navigateTo') {
+ try {
+ if (Object.keys(params).length) url = `${url}?data=${encodeURIComponent(JSON.stringify(params))}`
+ if (type === 'navigateBack') {
+ uni[type]({ delta: url })
+ } else {
+ uni[type]({ url })
+ }
+ } catch (error) {
+ console.error(error)
+ }
+}
+
+/**
+ * 预览图片
+ * @param {Array} urls 图片链接
+ */
+export function previewImage(urls, itemList = ['发送给朋友', '保存图片', '收藏']) {
+ uni.previewImage({
+ urls,
+ longPressActions: {
+ itemList,
+ fail: function (error) {
+ console.error(error,'===previewImage')
+ }
+ }
+ })
+}
+
+/**
+ * 保存图片到本地
+ * @param {String} filePath 图片临时路径
+ **/
+export function saveImage(filePath) {
+ if (!filePath) return false
+ uni.saveImageToPhotosAlbum({
+ filePath,
+ success: (res) => {
+ toast('图片保存成功', 'success')
+ },
+ fail: (err) => {
+ if (err.errMsg === 'saveImageToPhotosAlbum:fail:auth denied' || err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
+ uni.showModal({
+ title: '提示',
+ content: '需要您授权保存相册',
+ showCancel: false,
+ success: (modalSuccess) => {
+ uni.openSetting({
+ success(settingdata) {
+ if (settingdata.authSetting['scope.writePhotosAlbum']) {
+ uni.showModal({
+ title: '提示',
+ content: '获取权限成功,再次点击图片即可保存',
+ showCancel: false
+ })
+ } else {
+ uni.showModal({
+ title: '提示',
+ content: '获取权限失败,将无法保存到相册哦~',
+ showCancel: false
+ })
+ }
+ },
+ fail(failData) {
+ console.log('failData', failData)
+ }
+ })
+ }
+ })
+ }
+ }
+ })
+}
+
+/**
+ * 深拷贝
+ * @param {Object} data
+ **/
+export const clone = (data) => JSON.parse(JSON.stringify(data))
+
diff --git a/utils/weapp-jwt.js b/utils/weapp-jwt.js
new file mode 100644
index 0000000..cea62a1
--- /dev/null
+++ b/utils/weapp-jwt.js
@@ -0,0 +1,77 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
+exports.weBtoa = function (string) {
+ string = String(string);
+ var bitmap, a, b, c, result = "", i = 0, rest = string.length % 3;
+ for (; i < string.length;) {
+ if ((a = string.charCodeAt(i++)) > 255 ||
+ (b = string.charCodeAt(i++)) > 255 ||
+ (c = string.charCodeAt(i++)) > 255)
+ throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
+ bitmap = (a << 16) | (b << 8) | c;
+ result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
+ b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
+ }
+ return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
+};
+exports.weAtob = function (string) {
+ string = String(string).replace(/[\t\n\f\r ]+/g, "");
+ if (!b64re.test(string))
+ throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
+ string += "==".slice(2 - (string.length & 3));
+ var bitmap, result = "", r1, r2, i = 0;
+ for (; i < string.length;) {
+ bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 |
+ (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
+ result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) :
+ r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) :
+ String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
+ }
+ return result;
+};
+function b64DecodeUnicode(str) {
+ return decodeURIComponent(exports.weAtob(str).replace(/(.)/g, function (p) {
+ var code = p.charCodeAt(0).toString(16).toUpperCase();
+ if (code.length < 2) {
+ code = "0" + code;
+ }
+ return "%" + code;
+ }));
+}
+function base64_url_decode(str) {
+ var output = str.replace(/-/g, "+").replace(/_/g, "/");
+ switch (output.length % 4) {
+ case 0:
+ break;
+ case 2:
+ output += "==";
+ break;
+ case 3:
+ output += "=";
+ break;
+ default:
+ throw "Illegal base64url string!";
+ }
+ try {
+ return b64DecodeUnicode(output);
+ }
+ catch (err) {
+ return exports.weAtob(output);
+ }
+}
+function weappJwtDecode(token, options) {
+ if (typeof token !== "string") {
+ throw ("Invalid token specified");
+ }
+ options = options || {};
+ var pos = options.header === true ? 0 : 1;
+ try {
+ return JSON.parse(base64_url_decode(token.split(".")[pos]));
+ }
+ catch (e) {
+ throw ("Invalid token specified: " + e.message);
+ }
+}
+exports.default = weappJwtDecode;
\ No newline at end of file
diff --git a/vue.config.js b/vue.config.js
new file mode 100644
index 0000000..154b78a
--- /dev/null
+++ b/vue.config.js
@@ -0,0 +1,13 @@
+module.exports = {
+ devServer: {
+ proxy: {
+ '/api': {
+ target: 'http://qz.hschool.com.cn/',
+ changeOrigin: true,
+ pathRewrite: {
+ '^/api': ''
+ }
+ }
+ }
+ }
+}
\ No newline at end of file