diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39972d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +node_modules/ +unpackage/ +dist/ +.DS_Store +*.log +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.idea/ +.vscode/ +*.local +.hbuilderx/ +.vite/ +.cache/ +temp/ +*.tmp +*.temp diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..8c2b732 --- /dev/null +++ b/App.vue @@ -0,0 +1,17 @@ + + + diff --git a/config.js b/config.js new file mode 100644 index 0000000..5806535 --- /dev/null +++ b/config.js @@ -0,0 +1,11 @@ +const config = { + baseUrl: 'http://127.0.0.1:8503', + api: { + login: '/gw/login', + getQuestion: '/user/get_question', + answerQuestion: '/user/answer_question' + }, + timeout: 30000 +} + +export default config diff --git a/index.html b/index.html new file mode 100644 index 0000000..b5d330d --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..c1caf36 --- /dev/null +++ b/main.js @@ -0,0 +1,22 @@ +import App from './App' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + ...App +}) +app.$mount() +// #endif + +// #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..4aff211 --- /dev/null +++ b/manifest.json @@ -0,0 +1,72 @@ +{ + "name" : "qgdzs", + "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" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "3" +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..10beca0 --- /dev/null +++ b/pages.json @@ -0,0 +1,51 @@ +{ + "pages": [ + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页" + } + }, + { + "path": "pages/mine/mine", + "style": { + "navigationBarTitleText": "我的" + } + }, + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "登录", + "navigationStyle": "custom" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "qgdzs", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "tabBar": { + "color": "#7A7E83", + "selectedColor": "#667eea", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "fontSize": "14px", + "list": [ + { + "pagePath": "pages/index/index", + "iconPath": "", + "selectedIconPath": "", + "text": "首页" + }, + { + "pagePath": "pages/mine/mine", + "iconPath": "", + "selectedIconPath": "", + "text": "我的" + } + ] + }, + "uniIdRouter": {} +} diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..0f7cd54 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/pages/login/login.vue b/pages/login/login.vue new file mode 100644 index 0000000..9c73f99 --- /dev/null +++ b/pages/login/login.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/pages/mine/mine.vue b/pages/mine/mine.vue new file mode 100644 index 0000000..666afa3 --- /dev/null +++ b/pages/mine/mine.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/static/logo.png differ diff --git a/uni.promisify.adaptor.js b/uni.promisify.adaptor.js new file mode 100644 index 0000000..5fec4f3 --- /dev/null +++ b/uni.promisify.adaptor.js @@ -0,0 +1,13 @@ +uni.addInterceptor({ + returnValue (res) { + if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { + return res; + } + return new Promise((resolve, reject) => { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..b9249e9 --- /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 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$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:16px; + +/* 图片尺寸 */ +$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/api.js b/utils/api.js new file mode 100644 index 0000000..b8d79b3 --- /dev/null +++ b/utils/api.js @@ -0,0 +1,118 @@ +import config from '../config.js' +import storage from './storage.js' + +const request = (options) => { + return new Promise((resolve, reject) => { + uni.request({ + url: config.baseUrl + options.url, + method: options.method || 'GET', + data: options.data || {}, + header: { + 'Content-Type': 'application/json', + 'Authorization': storage.getToken() ? `Bearer ${storage.getToken()}` : '', + ...options.header + }, + timeout: config.timeout, + success: (res) => { + const { statusCode, data } = res + + if (statusCode === 200) { + if (data.code === 0 || data.success === true) { + resolve(data) + } else { + uni.showToast({ + title: data.message || '请求失败', + icon: 'none' + }) + reject(data) + } + } else if (statusCode === 401) { + storage.removeToken() + storage.removeUserInfo() + uni.reLaunch({ + url: '/pages/login/login' + }) + reject(res) + } else { + uni.showToast({ + title: '网络错误', + icon: 'none' + }) + reject(res) + } + }, + fail: (err) => { + uni.showToast({ + title: '网络连接失败', + icon: 'none' + }) + reject(err) + } + }) + }) +} + +const api = { + login(phone, code) { + return request({ + url: config.api.login, + method: 'POST', + data: { + phone, + code + } + }) + }, + + getQuestion() { + return request({ + url: config.api.getQuestion, + method: 'POST' + }) + }, + + answerQuestion(sn, answer) { + return request({ + url: config.api.answerQuestion, + method: 'POST', + data: { + sn, + answer + } + }) + }, + + get(url, data = {}) { + return request({ + url, + method: 'GET', + data + }) + }, + + post(url, data = {}) { + return request({ + url, + method: 'POST', + data + }) + }, + + put(url, data = {}) { + return request({ + url, + method: 'PUT', + data + }) + }, + + delete(url, data = {}) { + return request({ + url, + method: 'DELETE', + data + }) + } +} + +export default api diff --git a/utils/storage.js b/utils/storage.js new file mode 100644 index 0000000..4ef40fb --- /dev/null +++ b/utils/storage.js @@ -0,0 +1,69 @@ +const TOKEN_KEY = 'access_token' +const USER_INFO_KEY = 'user_info' +const QUESTION_KEY = 'question' +const ANSWERED_QUESTIONS_KEY = 'answered_questions' + +const storage = { + setToken(token) { + uni.setStorageSync(TOKEN_KEY, token) + }, + + getToken() { + return uni.getStorageSync(TOKEN_KEY) || '' + }, + + removeToken() { + uni.removeStorageSync(TOKEN_KEY) + }, + + setUserInfo(userInfo) { + uni.setStorageSync(USER_INFO_KEY, userInfo) + }, + + getUserInfo() { + return uni.getStorageSync(USER_INFO_KEY) || null + }, + + removeUserInfo() { + uni.removeStorageSync(USER_INFO_KEY) + }, + + setQuestion(question) { + uni.setStorageSync(QUESTION_KEY, question) + }, + + getQuestion() { + return uni.getStorageSync(QUESTION_KEY) || null + }, + + removeQuestion() { + uni.removeStorageSync(QUESTION_KEY) + }, + + addAnsweredQuestion(sn) { + const answeredQuestions = this.getAnsweredQuestions() + if (!answeredQuestions.includes(sn)) { + answeredQuestions.push(sn) + uni.setStorageSync(ANSWERED_QUESTIONS_KEY, answeredQuestions) + } + }, + + getAnsweredQuestions() { + return uni.getStorageSync(ANSWERED_QUESTIONS_KEY) || [] + }, + + isQuestionAnswered(sn) { + const answeredQuestions = this.getAnsweredQuestions() + return answeredQuestions.includes(sn) + }, + + clearAnsweredQuestions() { + uni.removeStorageSync(ANSWERED_QUESTIONS_KEY) + }, + + clearAll() { + uni.clearStorageSync() + } +} + +export default storage