commit 53af2dd84ef1d243c18a83564d7c315a4b45f4e4
Author: 陆亚狮 <2696699791@qq.com>
Date: Mon Apr 7 09:30:11 2025 +0800
init
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..f21e65c
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,63 @@
+
+
diff --git a/api/api.js b/api/api.js
new file mode 100644
index 0000000..f1bd11f
--- /dev/null
+++ b/api/api.js
@@ -0,0 +1,37 @@
+import request from '@/utils/request'
+//使用说明
+// export const getList = data => request.get('/api/list', data, false)
+// 页面调用名 请求参数 请求类型 接口地址 loading是否显示
+/*页面中调用方法:(若无请求参数则留空,例:this.$api.getList())
+this.$api.getList(params).then(res => {
+
+})
+*/
+//列表
+export const getList = data => request.get('/api/list', data)
+//登陆
+export const login = data => request.post('/api/login', data)
+//注册
+export const register = data => request.post('/api/register', data)
+//忘记密码
+export const forgetPassWord = data => request.post('/api/forgetPassWord', data)
+//登陆用户信息
+export const baseInfo = data => request.get('/api/baseinfo', data)
+//检测版本升级
+export const checkVersion = data => request.post('/api/checkVersion2', data,false)
+//文章详情
+export const detail = data => request.get('/api/detail', data,false)
+//获取单页内容
+export const page = data => request.get('/api/page', data)
+//提交实名认证资料
+export const auth = data => request.post('/api/auth', data)
+//修改密码
+export const password = data => request.post('/api/password', data)
+//注销帐号
+export const logout_account = data => request.post('/api/logout_account', data)
+//修改手机号
+export const phoneBind = data => request.get('/api/phoneBind', data)
+//修改邮箱
+export const emailBind = data => request.get('/api/emailBind', data)
+//提交反馈
+export const feedback = data => request.post('/api/feedback', data)
diff --git a/api/env.js b/api/env.js
new file mode 100644
index 0000000..d256ed8
--- /dev/null
+++ b/api/env.js
@@ -0,0 +1,11 @@
+let BASE_URL
+//开发环境中
+if (process.env.NODE_ENV === 'development') {
+ // 开发环境
+ BASE_URL = 'https://mock.apifox.cn/m1/3553664-0-default' //开发环境请求地址
+} else {
+ // 生产环境
+ BASE_URL = 'https://mock.apifox.cn/m1/3553664-0-default' //生成环境请求地址
+}
+
+export default BASE_URL
\ No newline at end of file
diff --git a/components/appUpdate/appUpdate.js b/components/appUpdate/appUpdate.js
new file mode 100644
index 0000000..0bbbf94
--- /dev/null
+++ b/components/appUpdate/appUpdate.js
@@ -0,0 +1,790 @@
+export default function(updateInfo) {
+ updateInfo.platform = updateInfo.platform ? updateInfo.platform : 'android'
+ updateInfo.mainColor = updateInfo.mainColor ? updateInfo.mainColor : 'FF5B78'
+ if (updateInfo.platform == 'android' || updateInfo.platform == 'ios') {
+
+ } else {
+ return false
+ }
+ let maskLayer = new plus.nativeObj.View('maskLayer', {
+ top: '0px',
+ left: '0px',
+ height: '100%',
+ width: '100%',
+ backgroundColor: 'rgba(0,0,0,0.5)'
+ })
+ let screenWidth = plus.screen.resolutionWidth
+ let screenHeight = plus.screen.resolutionHeight
+ const popupViewWidth = screenWidth * 0.7
+ const viewContentPadding = 20
+ const viewContentWidth = parseInt(popupViewWidth - (viewContentPadding * 2))
+ const descriptionList = drawtext((updateInfo.updateContent || '发现新版本'), viewContentWidth)
+ let popupViewHeight = 80 + 20 + 20 + 90 + 50
+ let popupViewContentList = [{
+ src: '/static/images/update.png',
+ id: "logo",
+ tag: "img",
+ position: {
+ top: "0px",
+ left: (popupViewWidth - 124) / 2 + "px",
+ width: "124px",
+ height: "80px",
+ }
+ },
+ {
+ tag: 'font',
+ id: 'title',
+ text: "发现新版本 " + (updateInfo.version || ''),
+ textStyles: {
+ size: '18px',
+ color: "#333",
+ weight: "bold",
+ whiteSpace: "normal"
+ },
+ position: {
+ top: '90px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "30px",
+ }
+ }
+ ]
+ const textHeight = 18
+ let contentTop = 130
+ descriptionList.forEach((item, index) => {
+ if (index > 0) {
+ popupViewHeight += textHeight;
+ contentTop += textHeight;
+ }
+ popupViewContentList.push({
+ tag: 'font',
+ id: 'content' + index + 1,
+ text: item.content,
+ textStyles: {
+ size: '14px',
+ color: "#666",
+ lineSpacing: "50%",
+ align: "left"
+ },
+ position: {
+ top: contentTop + "px",
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: textHeight + "px",
+ }
+ });
+ if (item.type == "break") {
+ contentTop += 10;
+ popupViewHeight += 10;
+ }
+ })
+ if (updateInfo.force) {
+ popupViewContentList.push({
+ tag: 'rect', //绘制底边按钮
+ rectStyles: {
+ radius: "6px",
+ color: updateInfo.mainColor
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "40px"
+ }
+ })
+ popupViewContentList.push({
+ tag: 'font',
+ id: 'confirmText',
+ text: "立即升级",
+ textStyles: {
+ size: '16px',
+ color: "#FFF",
+ lineSpacing: "0%",
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "40px"
+ }
+ })
+ } else {
+ popupViewContentList.push({
+ tag: 'rect',
+ id: 'cancelBox',
+ rectStyles: {
+ radius: "3px",
+ borderColor: "#f1f1f1",
+ borderWidth: "1px",
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ })
+ popupViewContentList.push({
+ tag: 'rect',
+ id: 'confirmBox',
+ rectStyles: {
+ radius: "3px",
+ color: updateInfo.mainColor,
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ })
+ popupViewContentList.push({
+ tag: 'font',
+ id: 'cancelText',
+ text: "暂不升级",
+ textStyles: {
+ size: '16px',
+ color: "#666",
+ lineSpacing: "0%",
+ whiteSpace: "normal"
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ })
+ popupViewContentList.push({
+ tag: 'font',
+ id: 'confirmText',
+ text: "立即升级",
+ textStyles: {
+ size: '16px',
+ color: "#FFF",
+ lineSpacing: "0%",
+ whiteSpace: "normal"
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ })
+ }
+ let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单
+ tag: "rect",
+ top: (screenHeight - popupViewHeight) / 2 + "px",
+ left: '15%',
+ height: popupViewHeight + "px",
+ width: "70%"
+ })
+ popupView.drawRect({
+ color: "#FFFFFF",
+ radius: "8px"
+ }, {
+ top: "40px",
+ height: popupViewHeight - 40 + "px",
+ })
+ popupView.draw(popupViewContentList)
+ popupView.addEventListener("click", e => {
+ let maxTop = popupViewHeight - viewContentPadding
+ let maxLeft = popupViewWidth - viewContentPadding
+ let buttonWidth = (viewContentWidth - viewContentPadding) / 2
+ if (e.clientY > maxTop - 30 && e.clientY < maxTop) {
+ if (updateInfo.force) {
+ if (e.clientX > viewContentPadding && e.clientX < maxLeft) {
+ maskLayer.hide()
+ popupView.hide()
+ let platform = updateInfo.platform || 'android'
+ let downUrl = updateInfo.downUrl || ''
+ download(updateInfo)
+ }
+ } else {
+ let maxTop = popupViewHeight - viewContentPadding;
+ let maxLeft = popupViewWidth - viewContentPadding;
+ let buttonWidth = (viewContentWidth - viewContentPadding) / 2;
+ if (e.clientY > maxTop - 30 && e.clientY < maxTop) {
+ // 暂不升级
+ if (e.clientX > viewContentPadding && e.clientX < maxLeft - buttonWidth -
+ viewContentPadding) {
+ maskLayer.hide()
+ popupView.hide()
+ }
+ if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
+ // 立即升级
+ maskLayer.hide()
+ popupView.hide()
+ let platform = updateInfo.platform || 'android'
+ let downUrl = updateInfo.downUrl || ''
+ download(updateInfo)
+ }
+ }
+ }
+ }
+ })
+ // 点击遮罩层
+ maskLayer.addEventListener("click", function() { //处理遮罩层点击
+ // maskLayer.hide();
+ // popupView.hide();
+ })
+ // 显示弹窗
+ maskLayer.show()
+ popupView.show()
+}
+
+// 下载流程
+function download(updateInfo) {
+ let platform = updateInfo.platform || 'android'
+ if (updateInfo.downUrl) {
+ if (platform == 'ios') {
+ plus.runtime.openURL(updateInfo.downUrl)
+ }
+ if (platform == 'android') {
+ getDownload(updateInfo)
+ }
+ } else {
+ plus.nativeUI.alert('下载地址无效')
+ }
+}
+
+// 从服务器下载应用资源包(wgt文件)
+const getDownload = function(data) {
+ let dtask
+ let popupData = {
+ progress: true,
+ buttonNum: 2
+ };
+ if(data.force){
+ popupData.buttonNum = 0
+ }
+
+ let lastProgressValue = 0
+ let popupObj = downloadPopup(popupData, data.mainColor)
+
+ dtask = plus.downloader.createDownload(data.downUrl, {
+ filename: "_doc/update/"
+ }, function(download, status) {
+ if (status == 200) {
+ popupObj.change({
+ progressValue: 100,
+ progressTip:"正在安装文件...",
+ progress: true,
+ buttonNum: 0
+ })
+ plus.runtime.install(download.filename, {}, function() {
+ popupObj.change({
+ contentText: "应用资源更新完成!",
+ buttonNum: 1,
+ progress: false
+ });
+ }, function(e) {
+ popupObj.cancel()
+ plus.nativeUI.alert("安装文件失败[" + e.code + "]:" + e.message);
+ });
+ } else {
+ popupObj.change({
+ contentText: "文件下载失败...",
+ buttonNum: 1,
+ progress: false
+ });
+ }
+ });
+ dtask.start()
+ dtask.addEventListener("statechanged", function(task, status) {
+ switch (task.state) {
+ case 1: // 开始
+ popupObj.change({
+ progressValue:0,
+ progressTip:"准备下载...",
+ progress: true
+ });
+ break;
+ case 2: // 已连接到服务器
+ popupObj.change({
+ progressValue:0,
+ progressTip:"开始下载...",
+ progress: true
+ });
+ break;
+ case 3:
+ const progress = parseInt(task.downloadedSize / task.totalSize * 100);
+ if(progress - lastProgressValue >= 2){
+ lastProgressValue = progress;
+ popupObj.change({
+ progressValue:progress,
+ progressTip: "已下载" + progress + "%",
+ progress: true
+ });
+ }
+ break;
+ }
+ })
+ // 取消下载
+ popupObj.cancelDownload = function(){
+ dtask && dtask.abort()
+ uni.showToast({
+ title: "已取消下载",
+ icon:"none"
+ });
+ }
+ // 重启APP
+ popupObj.reboot = function(){
+ plus.runtime.restart()
+ }
+}
+
+// 文件下载的弹窗绘图
+function downloadPopupDrawing(data, mainColor){
+ // 以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心
+ const screenWidth = plus.screen.resolutionWidth;
+ const screenHeight = plus.screen.resolutionHeight;
+ //弹窗容器宽度
+ const popupViewWidth = screenWidth * 0.7;
+
+ // 弹窗容器的Padding
+ const viewContentPadding = 20;
+ // 弹窗容器的宽度
+ const viewContentWidth = popupViewWidth - (viewContentPadding * 2);
+ // 弹窗容器高度
+ let popupViewHeight = viewContentPadding * 3 + 60;
+ let progressTip = data.progressTip || "准备下载...";
+ let contentText = data.contentText || "正在为您更新,请耐心等待";
+
+ let elementList = [
+ {
+ tag: 'rect', //背景色
+ color: '#FFFFFF',
+ rectStyles:{
+ radius: "8px"
+ }
+ },
+ {
+ tag: 'font',
+ id: 'title',
+ text: "升级APP",
+ textStyles: {
+ size: '16px',
+ color: "#333",
+ weight: "bold",
+ verticalAlign: "middle",
+ whiteSpace: "normal"
+ },
+ position: {
+ top: viewContentPadding + 'px',
+ height: "30px",
+ }
+ },
+ {
+ tag: 'font',
+ id: 'content',
+ text: contentText,
+ textStyles: {
+ size: '14px',
+ color: "#333",
+ verticalAlign: "middle",
+ whiteSpace: "normal"
+ },
+ position: {
+ top: viewContentPadding * 2 + 30 + 'px',
+ height: "20px",
+ }
+ }
+ ];
+ // 是否有进度条
+
+ if(data.progress){
+ popupViewHeight += viewContentPadding + 40
+ elementList = elementList.concat([
+ {
+ tag: 'font',
+ id: 'progressValue',
+ text: progressTip,
+ textStyles: {
+ size: '14px',
+ color: mainColor,
+ whiteSpace: "normal"
+ },
+ position: {
+ top: viewContentPadding * 4 + 20 + 'px',
+ height: "30px"
+ }
+ },
+ {
+ tag: 'rect', //绘制进度条背景
+ id: 'progressBg',
+ rectStyles:{
+ radius: "4px",
+ borderColor: "#f1f1f1",
+ borderWidth: "1px",
+ },
+ position:{
+ top: viewContentPadding * 4 + 60 + 'px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "8px"
+ }
+ },
+ ])
+ }
+
+ if (data.buttonNum == 2) {
+ popupViewHeight += viewContentPadding + 30;
+ elementList = elementList.concat([
+ {
+ tag: 'rect', //绘制底边按钮
+ rectStyles:{
+ radius: "3px",
+ borderColor: "#f1f1f1",
+ borderWidth: "1px",
+ },
+ position:{
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px"
+ }
+ },
+ {
+ tag: 'rect', //绘制底边按钮
+ rectStyles:{
+ radius: "3px",
+ color: mainColor
+ },
+ position:{
+ bottom: viewContentPadding + 'px',
+ left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px"
+ }
+ },
+ {
+ tag: 'font',
+ id: 'cancelText',
+ text: "取消下载",
+ textStyles: {
+ size: '14px',
+ color: "#666",
+ lineSpacing: "0%",
+ whiteSpace: "normal"
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ },
+ {
+ tag: 'font',
+ id: 'confirmText',
+ text: "后台下载",
+ textStyles: {
+ size: '14px',
+ color: "#FFF",
+ lineSpacing: "0%",
+ whiteSpace: "normal"
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+ width: (viewContentWidth - viewContentPadding) / 2 + "px",
+ height: "40px",
+ }
+ }
+ ]);
+ }
+
+ if (data.buttonNum == 1) {
+ popupViewHeight += viewContentPadding + 40;
+ elementList = elementList.concat([
+ {
+ tag: 'rect', //绘制底边按钮
+ rectStyles:{
+ radius: "6px",
+ color: $mainColor
+ },
+ position:{
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "40px"
+ }
+ },
+ {
+ tag: 'font',
+ id: 'confirmText',
+ text: "关闭",
+ textStyles: {
+ size: '14px',
+ color: "#FFF",
+ lineSpacing: "0%",
+ },
+ position: {
+ bottom: viewContentPadding + 'px',
+ left: viewContentPadding + "px",
+ width: viewContentWidth + "px",
+ height: "40px"
+ }
+ }
+ ]);
+ }
+
+ return {
+ popupViewHeight:popupViewHeight,
+ popupViewWidth:popupViewWidth,
+ screenHeight:screenHeight,
+ viewContentWidth:viewContentWidth,
+ viewContentPadding:viewContentPadding,
+ elementList: elementList
+ };
+}
+// 文件下载的弹窗
+function downloadPopup(data, mainColor) {
+
+ // 弹窗遮罩层
+ let maskLayer = new plus.nativeObj.View("maskLayer", { //先创建遮罩层
+ top: '0px',
+ left: '0px',
+ height: '100%',
+ width: '100%',
+ backgroundColor: 'rgba(0,0,0,0.5)'
+ });
+
+ let popupViewData = downloadPopupDrawing(data, mainColor);
+
+ // 弹窗内容
+ let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单
+ tag: "rect",
+ top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",
+ left: '15%',
+ height: popupViewData.popupViewHeight + "px",
+ width: "70%",
+ });
+ let progressValue = 0;
+ let progressTip = 0;
+ let contentText = 0;
+ let buttonNum = 2;
+ if(data.buttonNum >= 0){
+ buttonNum = data.buttonNum;
+ }
+ popupView.draw(popupViewData.elementList);
+ let callbackData = {
+ change: function(res) {
+ let progressElement = [];
+ if(res.progressValue){
+ progressValue = res.progressValue;
+ // 绘制进度条
+ progressElement.push({
+ tag: 'rect', //绘制进度条背景
+ id: 'progressValueBg',
+ rectStyles:{
+ radius: "4px",
+ color: mainColor
+ },
+ position:{
+ top: popupViewData.viewContentPadding * 4 + 60 + 'px',
+ left: popupViewData.viewContentPadding + "px",
+ width: popupViewData.viewContentWidth * (res.progressValue / 100) + "px",
+ height: "8px"
+ }
+ });
+ }
+ if(res.progressTip){
+ progressTip = res.progressTip;
+ progressElement.push({
+ tag: 'font',
+ id: 'progressValue',
+ text: res.progressTip,
+ textStyles: {
+ size: '14px',
+ color: mainColor,
+ whiteSpace: "normal"
+ },
+ position: {
+ top: popupViewData.viewContentPadding * 4 + 20 + 'px',
+ height: "30px"
+ }
+ });
+ }
+ if(res.contentText){
+ contentText = res.contentText;
+ progressElement.push({
+ tag: 'font',
+ id: 'content',
+ text: res.contentText,
+ textStyles: {
+ size: '16px',
+ color: "#333",
+ whiteSpace: "normal"
+ },
+ position: {
+ top: popupViewData.viewContentPadding * 2 + 30 + 'px',
+ height: "30px",
+ }
+ });
+ }
+ if(res.buttonNum >= 0 && buttonNum != res.buttonNum){
+ buttonNum = res.buttonNum;
+ popupView.reset();
+ popupViewData = downloadPopupDrawing(Object.assign({
+ progressValue:progressValue,
+ progressTip:progressTip,
+ contentText:contentText,
+ },res));
+ let newElement = [];
+ popupViewData.elementList.map((item,index) => {
+ let have = false;
+ progressElement.forEach((childItem,childIndex) => {
+ if(item.id == childItem.id){
+ have = true;
+ }
+ });
+ if(!have){
+ newElement.push(item);
+ }
+ });
+ progressElement = newElement.concat(progressElement);
+ popupView.setStyle({
+ tag: "rect",
+ top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",
+ left: '15%',
+ height: popupViewData.popupViewHeight + "px",
+ width: "70%",
+ });
+ popupView.draw(progressElement);
+ }else{
+ popupView.draw(progressElement);
+ }
+ },
+ cancel: function() {
+ maskLayer.hide();
+ popupView.hide();
+ }
+ }
+ popupView.addEventListener("click", function(e) {
+ let maxTop = popupViewData.popupViewHeight - popupViewData.viewContentPadding;
+ let maxLeft = popupViewData.popupViewWidth - popupViewData.viewContentPadding;
+ if (e.clientY > maxTop - 40 && e.clientY < maxTop) {
+ if(buttonNum == 1){
+ // 单按钮
+ if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft) {
+ maskLayer.hide();
+ popupView.hide();
+ callbackData.reboot();
+ }
+ }else if(buttonNum == 2){
+ // 双按钮
+ let buttonWidth = (popupViewData.viewContentWidth - popupViewData.viewContentPadding) / 2;
+ if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft - buttonWidth - popupViewData.viewContentPadding) {
+ maskLayer.hide();
+ popupView.hide();
+ callbackData.cancelDownload();
+ } else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
+ maskLayer.hide();
+ popupView.hide();
+ }
+ }
+ }
+ });
+ // 显示弹窗
+ maskLayer.show();
+ popupView.show();
+ // 改变进度条
+ return callbackData
+}
+
+// 文字换行
+function drawtext(text, maxWidth) {
+ let textArr = text.split("");
+ let len = textArr.length;
+ // 上个节点
+ let previousNode = 0;
+ // 记录节点宽度
+ let nodeWidth = 0;
+ // 文本换行数组
+ let rowText = [];
+ // 如果是字母,侧保存长度
+ let letterWidth = 0;
+ // 汉字宽度
+ let chineseWidth = 14;
+ // otherFont宽度
+ let otherWidth = 7;
+ for (let i = 0; i < len; i++) {
+ if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
+ if (letterWidth > 0) {
+ if (nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth) {
+ rowText.push({
+ type: "text",
+ content: text.substring(previousNode, i)
+ });
+ previousNode = i
+ nodeWidth = chineseWidth
+ letterWidth = 0
+ } else {
+ nodeWidth += chineseWidth + letterWidth * otherWidth
+ letterWidth = 0
+ }
+ } else {
+ if (nodeWidth + chineseWidth > maxWidth) {
+ rowText.push({
+ type: "text",
+ content: text.substring(previousNode, i)
+ })
+ previousNode = i
+ nodeWidth = chineseWidth
+ } else {
+ nodeWidth += chineseWidth
+ }
+ }
+ } else {
+ if (/\n/g.test(textArr[i])) {
+ rowText.push({
+ type: "break",
+ content: text.substring(previousNode, i)
+ })
+ previousNode = i + 1
+ nodeWidth = 0
+ letterWidth = 0
+ } else if (textArr[i] == "\\" && textArr[i + 1] == "n") {
+ rowText.push({
+ type: "break",
+ content: text.substring(previousNode, i)
+ })
+ previousNode = i + 2
+ nodeWidth = 0
+ letterWidth = 0
+ } else if (/[a-zA-Z0-9]/g.test(textArr[i])) {
+ letterWidth += 1;
+ if (nodeWidth + letterWidth * otherWidth > maxWidth) {
+ rowText.push({
+ type: "text",
+ content: text.substring(previousNode, i + 1 - letterWidth)
+ })
+ previousNode = i + 1 - letterWidth
+ nodeWidth = letterWidth * otherWidth
+ letterWidth = 0
+ }
+ } else {
+ if (nodeWidth + otherWidth > maxWidth) {
+ rowText.push({
+ type: "text",
+ content: text.substring(previousNode, i)
+ });
+ previousNode = i
+ nodeWidth = otherWidth
+ } else {
+ nodeWidth += otherWidth
+ }
+ }
+ }
+ }
+ if (previousNode < len) {
+ rowText.push({
+ type: "text",
+ content: text.substring(previousNode, len)
+ })
+ }
+ return rowText
+}
\ No newline at end of file
diff --git a/components/daySelect/index.vue b/components/daySelect/index.vue
new file mode 100644
index 0000000..3ed2e56
--- /dev/null
+++ b/components/daySelect/index.vue
@@ -0,0 +1,117 @@
+
+
+
+ {{ currentYear }}年 {{ currentMonth }}月
+
+
+
+
+ {{ item.day }}
+ 今天
+ 周{{ item.week }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/config.js b/config/config.js
new file mode 100644
index 0000000..6d3c1fc
--- /dev/null
+++ b/config/config.js
@@ -0,0 +1,17 @@
+
+let config = {
+ //不拦截页面路径
+ whiteList: [
+ '/pages/public/login',
+ '/pages/public/forget_password',
+ '/pages/public/register',
+ '/pages/index/index',
+ '/pages/index/list',
+ '/pages/subPack/index/detail',
+ //一行一个
+ ],
+ token : 'token', //本地存储token的变量名
+ login_page : '/pages/public/login', //拦截后跳转的登陆页路径
+ vconsole_status: 0, //是否启用调试工具,1为启用,0不启用
+}
+export default config
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..c3ff205
--- /dev/null
+++ b/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..3472935
--- /dev/null
+++ b/main.js
@@ -0,0 +1,47 @@
+import App from './App'
+import '@/utils/interceptor.js';//引入拦截
+
+import Vue from 'vue'
+import uView from '@/uni_modules/uview-ui'
+Vue.use(uView)
+
+import store from './store'
+
+// 注册请求方法
+import * as api from '@/api/api.js'
+Vue.prototype.$api = api
+
+
+import BASE_URL from '@/api/env.js' //引入接口共用地址
+Vue.prototype.$API_BASE_URL= BASE_URL
+
+import config from '@/config/config.js';
+Vue.prototype.$systemConfig = config
+
+let vuexStore = require("@/store/$u.mixin.js");
+Vue.mixin(vuexStore);
+
+//是否启用调试工具
+if(config.vconsole_status){
+ const vconsole = require('vconsole')
+ Vue.prototype.$vconsole = new vconsole() // 使用vconsole
+}
+
+
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+ store,
+ ...App
+})
+app.$mount()
+
+// #ifdef VUE3
+import { createSSRApp } from '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
new file mode 100644
index 0000000..c1671fd
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,91 @@
+{
+ "name" : "巡检保洁",
+ "appid" : "",
+ "description" : "",
+ "versionName" : "1.0.0",
+ "versionCode" : "100",
+ "transformPx" : false,
+ /* 5+App特有相关 */
+ "app-plus" : {
+ "usingComponents" : true,
+ "nvueStyleCompiler" : "uni-app",
+ "compilerVersion" : 3,
+ "splashscreen" : {
+ "alwaysShowBeforeRender" : true,
+ "waiting" : true,
+ "autoclose" : true,
+ "delay" : 0
+ },
+ /* 模块配置 */
+ "modules" : {
+ "Camera" : {}
+ },
+ /* 应用发布信息 */
+ "distribute" : {
+ /* android打包配置 */
+ "android" : {
+ "permissions" : [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ /* ios打包配置 */
+ "ios" : {},
+ /* SDK配置 */
+ "sdkConfigs" : {
+ "geolocation" : {
+ "system" : {
+ "__platform__" : [ "ios" ]
+ }
+ }
+ },
+ "splashscreen" : {
+ "androidStyle" : "default"
+ }
+ }
+ },
+ /* 快应用特有相关 */
+ "quickapp" : {},
+ /* 小程序特有相关 */
+ "mp-weixin" : {
+ "appid" : "",
+ "setting" : {
+ "urlCheck" : false,
+ "postcss" : true,
+ "minified" : true
+ },
+ "usingComponents" : true,
+ "optimization" : {
+ "subPackages" : true
+ }
+ },
+ "mp-alipay" : {
+ "usingComponents" : true
+ },
+ "mp-baidu" : {
+ "usingComponents" : true
+ },
+ "mp-toutiao" : {
+ "usingComponents" : true
+ },
+ "uniStatistics" : {
+ "enable" : false
+ },
+ "vueVersion" : "2"
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b2277a2
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "id": "liuyan814-unitempate",
+ "name": "巡检保洁",
+ "displayName": "巡检保洁",
+ "version": "1.0.6",
+ "description": "快速搭建uni-app项目,封装request,带页面拦截器,请求锁,带请求loading,集成uview,集成在线更新组件、集成调试工具vconsole,分包。",
+ "keywords": [
+ "封装request",
+ "页面拦截器",
+ "uview",
+ "图鸟UI",
+ "在线更新"
+ ],
+ "dcloudext": {
+ "category": [
+ "uni-app前端模板",
+ "前端页面模板"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..72802a3
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,222 @@
+{
+ // 如果您是通过uni_modules形式引入uView,可以忽略此配置
+ "easycom": {
+ "^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue"
+ },
+ "pages": [
+ {
+ "path": "pages/index/index",
+ "style": {
+ "navigationBarTitleText": "首页"
+ }
+ },
+ {
+ "path": "pages/index/list",
+ "style": {
+ "navigationBarTitleText": "保洁点位"
+ }
+ },
+ {
+ "path": "pages/index/cleanDetails",
+ "style": {
+ "navigationStyle": "custom" ,
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "保洁详情"
+ }
+ },
+ {
+ "path": "pages/index/cleanPlan",
+ "style": {
+ "navigationStyle": "custom" ,
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "保洁计划"
+ }
+ },
+ {
+ "path": "pages/index/planList",
+ "style": {
+ "navigationStyle": "custom" ,
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "计划列表"
+ }
+ },
+ {
+ "path": "pages/my/index",
+ "style": {
+ "navigationBarTitleText": "我的",
+ "navigationBarBackgroundColor": "#4790FF",
+ "navigationBarTextStyle": "white",
+ "enablePullDownRefresh": true
+
+ }
+ },
+ {
+ "path": "pages/public/login",
+ "style": {
+ "navigationBarTitleText": "登录"
+ }
+ },
+ {
+ "path" : "pages/my/profile",
+ "style" :
+ {
+ "navigationBarTitleText" : "个人信息",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/setting",
+ "style" :
+ {
+ "navigationBarTitleText" : "设置",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/password",
+ "style" :
+ {
+ "navigationBarTitleText" : "修改密码",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/index",
+ "style" :
+ {
+ "navigationBarTitleText" : "帐号&安全",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/about/index",
+ "style" :
+ {
+ "navigationBarTitleText" : "关于我们",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/phone",
+ "style" :
+ {
+ "navigationBarTitleText" : "手机号绑定",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/email",
+ "style" :
+ {
+ "navigationBarTitleText" : "邮箱绑定",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/account/logout_account",
+ "style" :
+ {
+ "navigationBarTitleText" : "注销帐号",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/auth",
+ "style" :
+ {
+ "navigationBarTitleText" : "实名认证",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/public/page",
+ "style" :
+ {
+ "navigationBarTitleText" : "",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/my/about/feedback",
+ "style" :
+ {
+ "navigationBarTitleText" : "意见反馈",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/public/register",
+ "style" :
+ {
+ "navigationBarTitleText" : "注册",
+ "enablePullDownRefresh" : false
+ }
+ },
+ {
+ "path" : "pages/public/forget_password",
+ "style" :
+ {
+ "navigationBarTitleText" : "忘记密码",
+ "enablePullDownRefresh" : false
+ }
+ }
+
+ ],
+ //分包加载配置,此配置为小程序的分包加载机制。
+ "subPackages": [
+ {
+ "root": "pages/subPack", //子包的根目录
+ "pages": [
+ {
+ "path": "index/detail",
+ "style": {
+ "navigationBarTitleText": "详情"
+ }
+ }
+
+ ]
+ }
+ ],
+
+ "globalStyle": {
+ "navigationBarTextStyle": "#211D2F",
+ "navigationBarTitleText": "uni-app",
+ "navigationBarBackgroundColor": "white",
+ "backgroundColor": "#F8F8F8"
+ },
+ "tabBar": {
+ "color": "#2D2D2D",
+ "selectedColor": "#4183F8",
+ "borderStyle": "white",
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "iconPath": "static/tab/home.png",
+ "selectedIconPath": "static/tab/home_cur.png",
+ "text": "首页"
+ },
+ {
+ "pagePath": "pages/index/list",
+ "iconPath": "static/tab/list.png",
+ "selectedIconPath": "static/tab/list_cur.png",
+ "text": "计划"
+ },
+ {
+ "pagePath": "pages/my/index",
+ "iconPath": "static/tab/my.png",
+ "selectedIconPath": "static/tab/my_cur.png",
+ "text": "我的"
+ }
+ ]
+ },
+
+ // 分包预载配置
+ "preloadRule": {
+ // 当我们进入了pages/index/index页面以后就会预下载pages/subPack分包
+ "pages/index/index": {
+ "network": "all", //在指定网络下预下载,可选值为:all(不限网络)、wifi(仅wifi下预下载)
+ "packages": ["pages/subPack"] //进入页面后预下载分包
+ }
+ },
+ "uniIdRouter": {}
+}
diff --git a/pages/detail.vue b/pages/detail.vue
new file mode 100644
index 0000000..5309fa1
--- /dev/null
+++ b/pages/detail.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 基本信息:
+
+ 订单编号:
+ {{item.order_sn}}
+
+
+ 派单信息:
+
+
+ 派单时间:
+ {{item.dispatch_time}}
+
+
+
+ 安装师傅:
+ {{item.master_name}}
+
+
+
+ 师傅电话:
+ {{item.master_tel}}
+
+
+
+
+
+
+
diff --git a/pages/form.vue b/pages/form.vue
new file mode 100644
index 0000000..4e085d2
--- /dev/null
+++ b/pages/form.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我已知晓并同意 《用户服务协议》及《隐私政策》
+
+
+
+
+ 提交注册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/cleanDetails.vue b/pages/index/cleanDetails.vue
new file mode 100644
index 0000000..9607b9a
--- /dev/null
+++ b/pages/index/cleanDetails.vue
@@ -0,0 +1,116 @@
+
+
+
+
+ 保洁区域名称
+ 所在区域:学校操场
+
+
+ 区域详情
+
+
+ 室内/室外
+ 区域类型
+
+
+ 保洁员1号
+ 保洁人员
+
+
+ 2024/1/27 9:53:35
+ 清扫时间
+
+
+ 清扫完成
+ 备注
+
+
+ 保洁区域图片
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/cleanPlan.vue b/pages/index/cleanPlan.vue
new file mode 100644
index 0000000..cf31785
--- /dev/null
+++ b/pages/index/cleanPlan.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+ 2024年11月21号
+ 08:30~11:30
+
+
+ {{ v.name }}
+
+
+
+
+
+ 待保洁
+
+
+ 东大门北侧_门2
+
+
+ 区域类型
+
+
+
+
+ {{ "需要清理整个户外通道/保持跑道整洁花坛边落叶清扫" }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
new file mode 100644
index 0000000..ec990c1
--- /dev/null
+++ b/pages/index/index.vue
@@ -0,0 +1,173 @@
+
+
+
+
+ 今日任务
+
+
+
+ 足球场休息室
+
+
+
+
+
+
+
+
+
+
+
+ 已保洁区域
+ 26 /50
+
+
+
+
+ 已保洁区域
+ 26 /50
+
+
+
+
+ 今日保洁计划名称
+
+ 00:00:00
+ 23:59:00
+
+
+
+
+
+
diff --git a/pages/index/list.vue b/pages/index/list.vue
new file mode 100644
index 0000000..32292c3
--- /dev/null
+++ b/pages/index/list.vue
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+ 保洁区域
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
diff --git a/pages/index/planList.vue b/pages/index/planList.vue
new file mode 100644
index 0000000..4c85a11
--- /dev/null
+++ b/pages/index/planList.vue
@@ -0,0 +1,90 @@
+
+
+
+ 424242
+
+
+
+
+ 已完成计划
+ 12
+
+
+ 未完成计划
+ 5
+
+
+
+
+
+
+
+ 05-21
+
+
+ 校门A区教学楼
+
+
+
+ 北大门右侧操场跑道/南广场升旗台/A区第二食堂3楼
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/about/feedback.vue b/pages/my/about/feedback.vue
new file mode 100644
index 0000000..900d697
--- /dev/null
+++ b/pages/my/about/feedback.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
diff --git a/pages/my/about/index.vue b/pages/my/about/index.vue
new file mode 100644
index 0000000..4ab3592
--- /dev/null
+++ b/pages/my/about/index.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/account/email.vue b/pages/my/account/email.vue
new file mode 100644
index 0000000..46a2112
--- /dev/null
+++ b/pages/my/account/email.vue
@@ -0,0 +1,116 @@
+
+
+
+ {{baseInfo.email}}
+
+
+
+
+
+
+
+
+
+ {{tips}}
+
+ 确定
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/my/account/index.vue b/pages/my/account/index.vue
new file mode 100644
index 0000000..32a5112
--- /dev/null
+++ b/pages/my/account/index.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 退出登陆
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/account/logout_account.vue b/pages/my/account/logout_account.vue
new file mode 100644
index 0000000..019b7d7
--- /dev/null
+++ b/pages/my/account/logout_account.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+ 我同意<<注销协议>>,提交后帐号将不再恢复
+
+
+ 注销帐号
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/account/password.vue b/pages/my/account/password.vue
new file mode 100644
index 0000000..18e125d
--- /dev/null
+++ b/pages/my/account/password.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/my/account/phone.vue b/pages/my/account/phone.vue
new file mode 100644
index 0000000..ca6e940
--- /dev/null
+++ b/pages/my/account/phone.vue
@@ -0,0 +1,120 @@
+
+
+
+ {{baseInfo.phone}}
+
+
+
+
+
+
+
+
+ {{tips}}
+
+ 确定
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/my/account/setting.vue b/pages/my/account/setting.vue
new file mode 100644
index 0000000..624c6bd
--- /dev/null
+++ b/pages/my/account/setting.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/auth.vue b/pages/my/auth.vue
new file mode 100644
index 0000000..bf21e37
--- /dev/null
+++ b/pages/my/auth.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/index.vue b/pages/my/index.vue
new file mode 100644
index 0000000..edc8e70
--- /dev/null
+++ b/pages/my/index.vue
@@ -0,0 +1,172 @@
+
+
+
+
+
+ {{baseInfo.name}}
+ 帐号:{{baseInfo.phone}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/my/profile.vue b/pages/my/profile.vue
new file mode 100644
index 0000000..efa333c
--- /dev/null
+++ b/pages/my/profile.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/forget_password.vue b/pages/public/forget_password.vue
new file mode 100644
index 0000000..790063e
--- /dev/null
+++ b/pages/public/forget_password.vue
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{tips}}
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/public/login.vue b/pages/public/login.vue
new file mode 100644
index 0000000..7837d74
--- /dev/null
+++ b/pages/public/login.vue
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 登录
+ 忘记密码
+ 没有帐号?注册
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/public/page.vue b/pages/public/page.vue
new file mode 100644
index 0000000..249e992
--- /dev/null
+++ b/pages/public/page.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
diff --git a/pages/public/register.vue b/pages/public/register.vue
new file mode 100644
index 0000000..b818145
--- /dev/null
+++ b/pages/public/register.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+ 我已知晓并同意 《用户服务协议》及《隐私政策》
+
+
+
+
+
+ 提交注册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/subPack/index/detail.vue b/pages/subPack/index/detail.vue
new file mode 100644
index 0000000..c2b5421
--- /dev/null
+++ b/pages/subPack/index/detail.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+ {{detail.title}}
+
+
+
+ {{detail.source}}
+ 发表于
+ {{detail.addtime}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tab_list.vue b/pages/tab_list.vue
new file mode 100644
index 0000000..3516ca9
--- /dev/null
+++ b/pages/tab_list.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 申请:{{item.master_id}}
+ 时间:{{item.addtime}}
+ 数量:{{item.total_nums}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/templates.vue b/pages/templates.vue
new file mode 100644
index 0000000..0df9ba1
--- /dev/null
+++ b/pages/templates.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/─ú░σ─┐┬╝.txt b/pages/─ú░σ─┐┬╝.txt
new file mode 100644
index 0000000..9dbcfbc
--- /dev/null
+++ b/pages/─ú░σ─┐┬╝.txt
@@ -0,0 +1 @@
+可把模板放在 \HBuilder X\templates\file\vue-page目录下面,这样可以在新建页面中,快速创建。
\ No newline at end of file
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..94da6f9
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,131 @@
+## 项目说明
+
+本项目可以快速搭建uni-app项目,封装request,集成z-paging(下拉刷新,上拉加载),带页面拦截器,请求锁,请求loading,集成uview,集成在线更新组件,集成本地调试工具vconsole、分包。
+
+## 接口开发
+
+接口服务器地址文件:**api/env.js**,修改服务器地址:
+
+```json
+let BASE_URL
+//开发环境中
+if (process.env.NODE_ENV === 'development') {
+ // 开发环境
+ BASE_URL = 'https://mock.apifox.com/m1/3553664-0-default' //开发环境请求地址
+} else {
+ // 生产环境
+ BASE_URL = 'https://mock.apifox.com/m1/3553664-0-default' //生成环境请求地址
+}
+
+export default BASE_URL
+```
+
+接口文件:**api/api.js**,在里面定义相关接口地址即可。
+
+```json
+//列表,GET方式请求
+export const getList = data => request.get('/api/list', data)
+//登陆,POST方式请求
+export const login = data => request.post('/api/login', data)
+//检测版本升级,POST方式请求,第三个参数(false)不显示loading加载
+export const checkVersion = data => request.post('/api/checkVersion', data,false)
+```
+
+页面中调用的方法:
+
+GET或POST调用如下:(无须导入接口方法,已在全局文件main.js中引入)
+
+```json
+//请求参数
+const params = {
+ page: pageNo,
+ limit: pageSize
+}
+//getList即对应api.js中的接口
+this.$api.getList(params).then(res => {
+ //todo....
+})
+```
+
+## 页面拦截器
+
+本项目集成了页面拦截器,页面拦截器即表示在白名单的页面URL不拦截,其他页面则拦截。
+
+场景:办公OA APP,只有登陆页面不需要拦截,其他页面则需要拦截。
+
+拦截器与token搭配使用,若是本地无TOKE,APP启动时打开首页,则自动会跳转到登陆页。若本地存在TOKEN,则打开首页时不会再要求登陆。
+
+页面拦截器配置文件在**config/config.js**
+
+以OA为例,登陆页不需要拦截则设置如下,还可添加其他不需要拦截的页面。
+
+```json
+let config = {
+ //不拦截页面路径
+ whiteList: [
+ '/pages/public/login'
+ ],
+ token : 'token', //本地存储token的变量名
+ login_page : '/pages/public/login' //拦截后跳转的登陆页路径
+}
+```
+
+ 注:封装请求文件(/utils/request.js)中,若服务器返回错误码大于400,则也跳转登陆页。
+
+```
+if(res.code > 400){
+ clearStorageSync('token')
+ useRouter(systemConfig.login_page, 'reLaunch')
+}else{
+ reslove(res)
+}
+```
+
+## 在线升级
+
+本项目集成了在线升级组件(仅支持APP),文件在:**components/appUpdate**,是否更新需要服务器返回如下JSON信息:
+
+```json
+{
+ "code": 0,
+ "platform": "android",
+ "version": "1.3.0",
+ "downUrl": "下载地址",
+ "updateContent": "修复BUG",
+ "force" : 0
+ }
+```
+
+> code为0时会提示更新,1则不弹出更新窗口。
+>
+> 测试更新弹出窗口,可修改api.js中的检测更新接口地址为:/api/checkVersion2
+
+## 本地调试工具vconsole
+
+本项目集成了本地调试工具vconsole,主要用于在生成APP或小程序后方便调试检查错误。
+
+若不需要开启,可以修改配置文件config/config.js是否开启:
+
+`vconsole_status: 1, //是否启用调试工具,1为启用,0不启用`
+
+## 分包
+
+ 增加分包功能,分包功能主要针对微信小程序,分包配置在pages.json中subPackages段内。如果不需要分包可以删除,并修改manifest.json 中"mp-weixin“段中 ` "subPackages" : true` 删除。
+
+## 集成UI
+
+本项目含集成了uview,z-paging,具体使用方法见官方文档。
+
+uview官方文档:[介绍 | uView - 多平台快速开发的UI框架 - uni-app UI框架](https://v1.uviewui.com/components/intro.html)
+
+z-paging官方文档:[介绍 | z-paging文档](https://z-paging.zxlee.cn/start/intro.html)(非常方便的实现上拉加载、下拉刷新等功能)
+
+## 其他说明
+
+**下载说明:建议单独下载文件后并解压,并在HB中打开目录进行演示,不要覆盖现在项目。**
+
+注:本项目中接口服务器和数据为mock数据,运行即可看到数据。
+
+登陆: 随机输入用户名和密码都可以登陆成功。
+
+如果在使用过程中遇到问题,可以在评论区反馈也可加微信liuyan814。
diff --git a/static/images/area-bg.png b/static/images/area-bg.png
new file mode 100644
index 0000000..d1d4119
Binary files /dev/null and b/static/images/area-bg.png differ
diff --git a/static/images/list.png b/static/images/list.png
new file mode 100644
index 0000000..953d783
Binary files /dev/null and b/static/images/list.png differ
diff --git a/static/images/list_cur.png b/static/images/list_cur.png
new file mode 100644
index 0000000..30b9857
Binary files /dev/null and b/static/images/list_cur.png differ
diff --git a/static/images/login_bg.png b/static/images/login_bg.png
new file mode 100644
index 0000000..4297c19
Binary files /dev/null and b/static/images/login_bg.png differ
diff --git a/static/images/logo.png b/static/images/logo.png
new file mode 100644
index 0000000..60091c2
Binary files /dev/null and b/static/images/logo.png differ
diff --git a/static/images/plan-bg.png b/static/images/plan-bg.png
new file mode 100644
index 0000000..a574622
Binary files /dev/null and b/static/images/plan-bg.png differ
diff --git a/static/images/plan-icon-bg.png b/static/images/plan-icon-bg.png
new file mode 100644
index 0000000..cf583e3
Binary files /dev/null and b/static/images/plan-icon-bg.png differ
diff --git a/static/images/pos-icon.png b/static/images/pos-icon.png
new file mode 100644
index 0000000..9db86a4
Binary files /dev/null and b/static/images/pos-icon.png differ
diff --git a/static/images/update.png b/static/images/update.png
new file mode 100644
index 0000000..33d6c48
Binary files /dev/null and b/static/images/update.png differ
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000..b2dade8
Binary files /dev/null and b/static/logo.png differ
diff --git a/static/tab/home.png b/static/tab/home.png
new file mode 100644
index 0000000..3aefa52
Binary files /dev/null and b/static/tab/home.png differ
diff --git a/static/tab/home_cur.png b/static/tab/home_cur.png
new file mode 100644
index 0000000..e7fe9e6
Binary files /dev/null and b/static/tab/home_cur.png differ
diff --git a/static/tab/list.png b/static/tab/list.png
new file mode 100644
index 0000000..975a5a0
Binary files /dev/null and b/static/tab/list.png differ
diff --git a/static/tab/list_cur.png b/static/tab/list_cur.png
new file mode 100644
index 0000000..77a0cd9
Binary files /dev/null and b/static/tab/list_cur.png differ
diff --git a/static/tab/my.png b/static/tab/my.png
new file mode 100644
index 0000000..cba9f6a
Binary files /dev/null and b/static/tab/my.png differ
diff --git a/static/tab/my_cur.png b/static/tab/my_cur.png
new file mode 100644
index 0000000..67ccfd5
Binary files /dev/null and b/static/tab/my_cur.png differ
diff --git a/store/$u.mixin.js b/store/$u.mixin.js
new file mode 100644
index 0000000..94ed2ee
--- /dev/null
+++ b/store/$u.mixin.js
@@ -0,0 +1,27 @@
+import { mapState } from 'vuex'
+import store from "@/store"
+
+// 尝试将用户在根目录中的store/index.js的vuex的state变量,全部加载到全局变量中
+let $uStoreKey = [];
+try{
+ $uStoreKey = store.state ? Object.keys(store.state) : [];
+}catch(e){
+
+}
+
+module.exports = {
+ created() {
+ // 将vuex方法挂在到$u中
+ // 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.$u.vuex('user.name', '史诗')
+ // 如果要修改vuex的state的version变量为1.0.1 => this.$u.vuex('version', '1.0.1')
+ this.$u.vuex = (name, value) => {
+ this.$store.commit('$uStore', {
+ name,value
+ })
+ }
+ },
+ computed: {
+ // 将vuex的state中的所有变量,解构到全局混入的mixin中
+ ...mapState($uStoreKey)
+ }
+}
\ No newline at end of file
diff --git a/store/index.js b/store/index.js
new file mode 100644
index 0000000..33ce954
--- /dev/null
+++ b/store/index.js
@@ -0,0 +1,64 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+Vue.use(Vuex)
+
+let lifeData = {};
+
+try{
+ // 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的
+ lifeData = uni.getStorageSync('lifeData');
+}catch(e){
+
+}
+
+// 需要永久存储,且下次APP启动需要取出的,在state中的变量名
+let saveStateKeys = ['vuex_user', 'vuex_token'];
+
+// 保存变量到本地存储中
+const saveLifeData = function(key, value){
+ // 判断变量名是否在需要存储的数组中
+ if(saveStateKeys.indexOf(key) != -1) {
+ // 获取本地存储的lifeData对象,将变量添加到对象中
+ let tmp = uni.getStorageSync('lifeData');
+ // 第一次打开APP,不存在lifeData变量,故放一个{}空对象
+ tmp = tmp ? tmp : {};
+ tmp[key] = value;
+ // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中
+ uni.setStorageSync('lifeData', tmp);
+ }
+}
+const store = new Vuex.Store({
+ // 下面这些值仅为示例,使用过程中请删除
+ state: {
+ // 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
+ // 加上vuex_前缀,是防止变量名冲突,也让人一目了然
+ vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {name: '明月'},
+ vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '',
+ // 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式
+ vuex_version: '1.0.1',
+ },
+ mutations: {
+ $uStore(state, payload) {
+ // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1
+ let nameArr = payload.name.split('.');
+ let saveKey = '';
+ let len = nameArr.length;
+ if(nameArr.length >= 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就是一个普通变量的情况
+ state[payload.name] = payload.value;
+ saveKey = payload.name;
+ }
+ // 保存变量到本地,见顶部函数定义
+ saveLifeData(saveKey, state[saveKey])
+ }
+ }
+})
+
+export default store
\ No newline at end of file
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..6fe4b58
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+@import '@/uni_modules/uview-ui/theme.scss';
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;
diff --git a/utils/common.js b/utils/common.js
new file mode 100644
index 0000000..4d901c1
--- /dev/null
+++ b/utils/common.js
@@ -0,0 +1,88 @@
+//获取当前时间,格式YYYY-MM-DD HH:MM:SS
+const GetNowTime = time => {
+ var date = time,
+ year = date.getFullYear(),
+ month = date.getMonth() + 1,
+ day = date.getDate(),
+ hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(),
+ minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(),
+ second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
+ month >= 1 && month <= 9 ? (month = "0" + month) : "";
+ day >= 0 && day <= 9 ? (day = "0" + day) : "";
+ // var timer = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
+ var timer = year + '-' + month + '-' + day;
+ return timer;
+}
+
+// 格式化电话号码
+const GetPhone = phone => {
+ let tel = phone.slice(0, 3) + '****' + phone.slice(7, 11);
+ return tel;
+}
+//返回日期和周几数组
+function weekDate() {
+ const myDate = new Date();
+ const padZero = num => String(num).padStart(2, '0'); // 补零工具函数
+
+ const dayList = [];
+
+ // 生成当天数据(补零)
+ dayList.push({
+ day: padZero(myDate.getDate()),
+ month: padZero(myDate.getMonth() + 1),
+ week: toWeekDay(myDate.getDay()),
+ year: myDate.getFullYear()
+ });
+
+ // 生成后续10天数据
+ for (let i = 0; i < 10; i++) {
+ myDate.setDate(myDate.getDate() + 1);
+ dayList.push({
+ day: padZero(myDate.getDate()),
+ month: padZero(myDate.getMonth() + 1),
+ week: toWeekDay(myDate.getDay()),
+ year: myDate.getFullYear()
+ });
+ }
+
+ // 返回标准化日期格式
+ return {
+ dayList,
+ StartDate: `${dayList[0].year}-${dayList[0].month}-${dayList[0].day}`,
+ EndDate: `${dayList[dayList.length - 1].year}-${dayList[dayList.length - 1].month}-${dayList[dayList.length - 1].day}`
+ };
+}
+
+function toWeekDay(weekDay) { // 传入数据 讲一周的某一天返回成中文状态下的字符
+ switch (weekDay) {
+ case 1:
+ return '一';
+ break;
+ case 2:
+ return '二';
+ break;
+ case 3:
+ return '三';
+ break;
+ case 4:
+ return '四';
+ break;
+ case 5:
+ return '五';
+ break;
+ case 6:
+ return '六';
+ break;
+ case 0:
+ return '日';
+ break;
+ default:
+ break;
+ }
+ return '传入未知参数';
+}
+module.exports = {
+ GetNowTime,
+ GetPhone,
+ weekDate
+}
\ No newline at end of file
diff --git a/utils/interceptor.js b/utils/interceptor.js
new file mode 100644
index 0000000..0e6ce41
--- /dev/null
+++ b/utils/interceptor.js
@@ -0,0 +1,50 @@
+
+import systemConfig from '@/config/config.js';
+// 页面白名单,不受拦截
+const whiteList = systemConfig.whiteList
+function hasPermission (url) {
+ let islogin = uni.getStorageSync(systemConfig.token );//isLogin是登录成功后在本地存储登录标识,存储一个能够判断用户登录的唯一标识就行
+ // 在白名单中或有登录判断条件可以直接跳转
+ if(whiteList.indexOf(url) !== -1 || islogin) {
+ //console.log('通过')
+ return true
+ }
+ //console.log('失败')
+ return false
+}
+uni.addInterceptor('navigateTo', {
+ // 页面跳转前进行拦截, invoke根据返回值进行判断是否继续执行跳转
+ invoke (e) {
+ const url = e.url.split('?')[0]
+ if(!hasPermission(url)){
+ uni.reLaunch({
+ url:systemConfig.login_page
+ })
+ return false
+ }
+ return true
+ },
+ success (e) {
+
+ }
+})
+
+uni.addInterceptor('switchTab', {
+ // tabbar页面跳转前进行拦截
+ invoke (e) {
+
+ const url = e.url.split('?')[0]
+ if(!hasPermission(url)){
+ uni.reLaunch({
+ url: systemConfig.login_page
+ })
+ //console.log('不在白名单内')
+ return false
+ }
+ //console.log('在白名单内')
+ return true
+ },
+ success (e) {
+
+ }
+})
\ No newline at end of file
diff --git a/utils/request.js b/utils/request.js
new file mode 100644
index 0000000..4851b88
--- /dev/null
+++ b/utils/request.js
@@ -0,0 +1,62 @@
+
+
+import BASE_URL from '@/api/env.js' //引入接口共用地址
+import RequestManager from '@/utils/requestManager.js'
+import {toast, clearStorageSync, getStorageSync, useRouter} from '@/utils/utils.js'
+import systemConfig from '@/config/config.js';
+const manager = new RequestManager()
+
+const baseRequest = async (url, method, data = {}, loading = true) =>{
+ let requestId = manager.generateId(method, url, data)
+ if(!requestId) {
+ console.log('重复请求')
+ }
+ if(!requestId)return false;
+
+ const header = {}
+ header.Authorization = getStorageSync(systemConfig.token) || ''
+ return new Promise((reslove, reject) => {
+ loading && uni.showLoading({title: 'loading'})
+ uni.request({
+ url: BASE_URL + url,
+ method: method || 'GET',
+ header: header,
+ timeout: 10000,
+ data: data || {},
+ complete: ()=>{
+ uni.hideLoading()
+ manager.deleteById(requestId)
+ },
+ success: (successData) => {
+ //console.log(successData)
+ const res = successData.data
+ if(successData.statusCode == 200){
+ // 业务逻辑,自行修改,401是服务器上返回该token过期,过期后跳转到登陆页面
+ if(res.code > 400){
+ clearStorageSync('token')
+ useRouter(systemConfig.login_page, 'reLaunch')
+ }else{
+ reslove(res)
+ }
+ }else{
+ console.log('网络连接失败,请稍后重试' ,url)
+ toast('网络连接失败,请稍后重试')
+ reject(res)
+ }
+ },
+ fail: (msg) => {
+ console.log("请求:"+BASE_URL + url +',发生错误:', err)
+ 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..0ff3976
--- /dev/null
+++ b/utils/utils.js
@@ -0,0 +1,475 @@
+/**
+ * 提示方法
+ * @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} url
+ * @return {function}
+ * @description navigateTo跳转
+ */
+export function Jump(url) {
+ uni.navigateTo({
+ url: url
+ })
+}
+
+
+
+/**
+ * 提示信息
+ * **/
+export function showModal(title, msg, showCancel) {
+ uni.showModal({
+ title: title,
+ content: msg,
+ showCancel: showCancel,
+ success: function(res) {
+
+ }
+ })
+}
+
+
+export function showLoading(content) {
+ uni.showLoading({
+ title: content
+ })
+}
+/**
+ * 隐藏loading
+ * **/
+export function hideLoading() {
+ uni.hideLoading()
+}
+
+/***
+ * 获取时间戳
+ */
+export function getTimStamp() {
+ var timestamp = Date.parse(new Date());
+ timestamp = timestamp / 1000;
+ return timestamp;
+}
+/***
+ * 生成随机数
+ */
+export function getNonce() {
+ var t = '';
+ for (var i = 0; i < 12; i++) {
+ t += Math.floor(Math.random() * 10);
+ }
+ return t;
+}
+/**
+ * 获取32位随机数
+ * ***/
+export function getnoncestr() {
+ let len = len || 32;
+ var $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ var maxPos = $chars.length;
+ var pwd = '';
+ for (var i = 0; i < len; i++) {
+ pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
+ }
+ return pwd;
+}
+
+/**
+ * 解析url中的参数
+ */
+export function UrlParamHash(url) {
+ var params = {},
+ h;
+ var hash = url.slice(url.indexOf("?") + 1).split("&");
+ for (var i = 0; i < hash.length; i++) {
+ h = hash[i].split("=");
+ if (h.length > 1) {
+ params[h[0]] = h[1];
+ } else {
+ params[h[0]] = "";
+ }
+ }
+ return params;
+}
+
+
+/**
+ * 一键复制 uni.setClipboardData
+ * 用法:
+ * 1. import {setClipboardData} from '该文件的地址'
+ * 2. 利用async await
+ * 3. await setClipboardData(需要复制的文本)
+ */
+const setClipboardData = (text) =>{
+ return new Promise((resolve,reject)=>{
+ uni.setClipboardData({
+ data: text,
+ success: (res) => {
+ resolve(res)
+ },
+ fail: (err) => {
+ reject(err)
+ }
+ })
+ })
+}
+
+/**
+ * 获取系统剪贴板内容 uni.getClipboardData
+ * 用法:
+ * 1. import {getClipboardData} from '该文件的地址'
+ * 2. 利用async await来接收获取到的数据
+ * 3. await getClipboardData()
+ */
+const getClipboardData = () =>{
+ return new Promise((resolve,reject)=>{
+ uni.getClipboardData({
+ success: (res) => {
+ resolve(res)
+ },
+ fail: (err) => {
+ reject(err)
+ }
+ })
+ })
+}
+
+/**
+ * 拨打电话 uni.makePhoneCall()
+ * 用法:
+ * 1. import {getBatteryInfo} from '该文件的地址'
+ * 2. 直接makePhoneCall(拨打的电话号码)
+ */
+const makePhoneCall = (phone) =>{
+ uni.makePhoneCall({
+ phoneNumber:phone
+ })
+}
+
+
+/**
+ * 设置缓存
+ * @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))
+ /**
+ * 获取平台名称
+ * @return {string} 平台名称
+ */
+export function getPlatform() {
+ let platform;
+ switch (process.env.VUE_APP_PLATFORM) {
+ case 'app':
+ case 'app-plus':
+ let n = uni.getSystemInfoSync().platform.toLowerCase();
+ if (n === 'ios') {
+ platform = 'ios';
+ } else if (n === 'android') {
+ platform = 'android';
+ } else {
+ platform = 'app';
+ }
+ break;
+ case 'mp-weixin':
+ platform = 'wx';
+ break;
+ case 'mp-alipay':
+ platform = 'alipay';
+ break;
+ case 'mp-baidu':
+ platform = 'baidu';
+ break;
+ case 'mp-qq':
+ platform = 'qq';
+ break;
+ case 'mp-toutiao':
+ platform = 'toutiao';
+ break;
+ case 'quickapp-webview':
+ platform = 'kuai';
+ break;
+ }
+
+ return platform;
+}
+
+/**
+ * 数组去重
+ * @param {Array} array 数值
+ * @retrun {Array} 数值
+ */
+export function arrayShuffle(array) {
+ let i = array.length, t, j;
+ while (i) {
+ j = Math.floor(Math.random() * i--);
+ t = array[i];
+ array[i] = array[j];
+ array[j] = t;
+ }
+ return array;
+}
+
+/**
+ * 日期格式化
+ * @param {Date} date 日期
+ * @param {string} format 返回的日期格式
+ * @retrun {string} 日期
+ */
+export function dateFormat(date, format = 'YYYY-MM-DD HH:mm:ss') {
+ const config = {
+ YYYY: date.getFullYear(),
+ MM: date.getMonth()+1,
+ DD: date.getDate(),
+ HH: date.getHours(),
+ mm: date.getMinutes(),
+ ss: date.getSeconds(),
+ }
+ for(const key in config){
+ let value = config[key];
+ if (value < 10) {
+ value = '0' + value;
+ }
+ format = format.replace(key, value)
+ }
+ return format
+}
+
+/**
+ * base64转文件
+ * @param {string} base64data base64
+ * @param {Function} cb 回调
+ */
+export function base64ToSrc(base64data, cb) {
+ const FILE_BASE_NAME = 'tmp_base64src';
+ const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
+ if (!format) {
+ return (new Error('格式错误'));
+ }
+
+ // #ifdef MP-WEIXIN
+ let filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
+ // #endif
+ // #ifdef MP-QQ
+ let filePath = `${qq.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
+ // #endif
+
+ const buffer = uni.base64ToArrayBuffer(bodyData);
+ uni.getFileSystemManager().writeFile({
+ filePath,
+ data: buffer,
+ encoding: 'binary',
+ success() {
+ cb && cb(filePath);
+ }
+ });
+}
+
+/**
+ * base64解码
+ * @param {string} str str
+ * @param {string}
+ */
+export function encodeBase64(str) {
+ return new Buffer.from(str).toString('base64');
+}
+
+/**
+ * base64解码
+ * @param {string} str str
+ * @param {string}
+ */
+export function decodeBase64(str) {
+ const commonContent = str.replace(/\s/g, '+');
+ return new Buffer.from(commonContent, 'base64').toString();
+}
+
+/**
+ * 播放声音
+ * @param {string} src 声音文件地址
+ * @param {Boolean} loop 是否循环
+ */
+export function playSound(src, loop = false) {
+ const innerAudioContext = uni.createInnerAudioContext();
+ innerAudioContext.autoplay = true;
+ innerAudioContext.loop = loop;
+ innerAudioContext.src = src;
+ innerAudioContext.onPlay(() => {});
+ innerAudioContext.onError((res) => {});
+}
+
+/**
+ * 生成订单ID
+ * @param {string} prefix 订单前缀
+ * @param {string} 订单ID
+ */
+export function createOrderSn(prefix = '') {
+ return `${prefix}${this.randomString(10).toUpperCase()}${+new Date()}`;
+}
+
+/**
+ * 图片转base64
+ * @param {string} src 图片地址
+ * @return {Promise} base64
+ */
+export function imageToBase64(src) {
+ return new Promise((resolve, reject) => {
+ uni.getImageInfo({
+ src,
+ success: image => {
+ console.log(image);
+ uni.getFileSystemManager().readFile({
+ filePath: image.path,
+ encoding: 'base64',
+ success: e => {
+ return resolve(`data:image/jpeg;base64,${e.data}`);
+ },
+ fail: e => {
+ return reject(null);
+ }
+ })
+ }
+ });
+ })
+}
+
+
+/**
+ * 随机范围内的数字
+ * @param {number} start 起始数字
+ * @param {number} end 起始数字
+ * @return {number || null} 随机数
+ */
+export function randomByRange(start, end){
+ if (typeof start === 'number' && typeof end === 'number') {
+ return start + Math.floor(Math.random() * (end - start));
+ } else {
+ console.error('参数必须为数字');
+ return null;
+ }
+}
\ No newline at end of file