32ab1e6f by 杨炀

init

0 parents
Showing 309 changed files with 4881 additions and 0 deletions
1 .DS_Store
2 node_modules/
3 unpackage/
4
5 package-lock.json
6 yarn.lock
1 { // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
2 // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
3 "version": "0.0",
4 "configurations": [{
5 "default" :
6 {
7 "launchtype" : "local"
8 },
9 "mp-weixin" :
10 {
11 "launchtype" : "local"
12 },
13 "type" : "uniCloud"
14 }
15 ]
16 }
1 <script>
2 import * as loginServer from '@/common/login.js';
3 import * as api from '@/common/api.js';
4 import config from '@/config.js';
5
6
7 let firstload = false
8 export default {
9 onLaunch: function() {
10 console.log('App Launch');
11 firstload = true
12 this.globalData.baseUrl = config.baseUrl;
13 this.globalData.baseUrl_api = config.baseUrl_api;
14 this.globalData.fileUrl = config.fileUrl;
15 uni.getSystemInfo({
16 success: function(res) {
17 console.log(111, res)
18 const model = res.model
19 let stt = ''
20 // 判断机型
21 if (model.includes('iPhone')) {
22 stt = 'iPhone'
23 } else if (model.includes('iPad')) {
24 stt = 'iPad'
25 } else if (model.includes('Android')) {
26 stt = 'Android'
27 } else {
28 stt = '其他'
29 }
30 uni.setStorageSync('systemType', stt);
31 }
32 })
33
34 new Promise((resolve, reject) => {
35 uni.checkSession({
36 success: res => {
37 loginServer
38 .getCurrUser(true)
39 .catch(() => {
40 return loginServer.pcLogin();
41 })
42 .then(user => {
43 resolve(user);
44 });
45 },
46 fail: res => {
47 loginServer
48 .wxLogin()
49 .then(loginRes => {
50 return loginServer.pcLogin(loginRes.code);
51 })
52 .then(user => {
53 resolve(user);
54 });
55 }
56 });
57
58 // loginServer
59 // .wxLogin()
60 // .then(loginRes => {
61 // return loginServer.pcLogin(loginRes.code)
62
63 // })
64 // .then(loginServer.getCurrUser)
65 // .then(user=>{
66 // resolve(user);
67 // });
68 })
69 .then(() => {
70 this.globalData.isLogin = true;
71 let firstLoadCallback = getApp().firstLoadCallback;
72 if (firstLoadCallback) {
73 firstLoadCallback();
74 }
75 });
76 },
77 onShow: function() {
78 console.log('App Show', uni.getStorageSync('isRegister'));
79 },
80 onHide: function() {
81 console.log('App Hide');
82 const isRegister = uni.getStorageSync('isRegister')
83 if (isRegister == '0') {
84 uni.setStorageSync('isRegister', '1');
85 }
86 }
87 };
88 </script>
89
90 <style lang="scss">
91 /*每个页面公共css */
92 @import '/common/uni.css';
93 @import '/common/mystyle.scss';
94 @import '@/static/font/iconfont.css';
95 </style>
...\ No newline at end of file ...\ No newline at end of file
1 import request from './request.js'
2 const accountInfo = uni.getAccountInfoSync()
3 const appId = accountInfo.miniProgram.appId;
4 import config from '@/config.js'
5 import * as loginServer from '@/common/login.js';
6
7 export function getUserExtByUserId(params) {
8 return request({
9 url: `/system/userExt/getUserExtByUserId`,
10 method: 'get'
11 })
12 }
13 export function getUserIsPay(params) {
14 return request({
15 url: `/system/order/getUserIsPay`,
16 method: 'get',
17 params: params
18 })
19 }
20 export function getVipPrice(params) {
21 return request({
22 url: `/system/config/configKey/sys.user.mem`,
23 method: 'get'
24 })
25 }
26 export function getMyCourses() {
27 return request({
28 url: `/system/course/getMyCourses`,
29 method: 'get'
30 })
31 }
32 export function getMyActivitys() {
33 return request({
34 url: `/system/activity/getMyActivitys`,
35 method: 'get'
36 })
37 }
38 export function getClassifyList() {
39 return request({
40 url: `/system/paper/getClassifyList`,
41 method: 'get'
42 })
43 }
44 export function getHomePageHot() {
45 return request({
46 url: `/system/paper/getHomePageHot`,
47 method: 'get'
48 })
49 }
50
51 export function getHomeTop() {
52 return request({
53 url: `/system/paper/list?isTop=1`,
54 method: 'get'
55 })
56 }
57 export function getPaperList(params) {
58 return request({
59 url: `/system/paper/list`,
60 method: 'get',
61 params: params
62 })
63 }
64 export function getCourseList(params) {
65 return request({
66 url: `/system/course/list`,
67 method: 'get',
68 params: params
69 })
70 }
71 export function getActivityList(params) {
72 return request({
73 url: `/system/activity/list`,
74 method: 'get',
75 params: params
76 })
77 }
78 export function getHomePageHotCourse(params) {
79 return request({
80 url: `/system/course/getHomePageHot`,
81 method: 'get',
82 params: params
83 })
84 }
85 export function getHomePageHotActive(params) {
86 return request({
87 url: `/system/activity/getHomePageHot`,
88 method: 'get',
89 params: params
90 })
91 }
92 export function getCourseById(courseId) {
93 return request({
94 url: `/system/course/${courseId}`,
95 method: 'get'
96 })
97 }
98 export function getActiveById(activityId) {
99 return request({
100 url: `/system/activity/${activityId}`,
101 method: 'get'
102 })
103 }
104 export function getUserAnswerList(params) {
105 return request({
106 url: `/system/userAnswer/getUserAnswersByUserId`,
107 method: 'get',
108 params: params
109 })
110 }
111 export function getUserAnswerInfo(params) {
112 return request({
113 url: `/system/userAnswer/getUserAnswerInfo`,
114 method: 'get',
115 params: params
116 })
117 }
118
119 export function getUserAnswerResult(params) {
120 return request({
121 url: `/system/userAnswer/getUserAnswerResult`,
122 method: 'get',
123 params: params
124 })
125 }
126
127 export function getPaperInfo(paperId) {
128 return request({
129 url: `/system/paper/${paperId}`,
130 method: 'get'
131 })
132 }
133 export function getCurrentUserInfo() {
134 return request({
135 url: `/system/user/getCurrentUserInfo`,
136 method: 'get'
137 })
138 }
139 export function updateUserInfo(form) {
140 return request({
141 url: `/system/user/updateUserInfo`,
142 method: 'put',
143 params: form
144 })
145 }
146 export function submitAnswer(form) {
147 return request({
148 url: `/system/userAnswer/submit`,
149 method: 'post',
150 params: form
151 })
152 }
153 export function unSubscribe(form) {
154 return request({
155 url: `/system/order/unSubscribe`,
156 method: 'post',
157 params: form
158 })
159 }
160 export function createOrder(form) {
161 return request({
162 url: `/system/pay/createOrder`,
163 method: 'post',
164 params: form
165 })
166 }
167 export function payForOrder(form) {
168 return request({
169 url: `/system/pay/payForOrder`,
170 method: 'post',
171 params: form
172 })
173 }
174 export function submitOrder(form) {
175 return request({
176 url: `/system/order/sumbit`,
177 method: 'post',
178 params: form
179 })
180 }
181 export function saveAnswer(form) {
182 return request({
183 url: `/system/userAnswer/save`,
184 method: 'post',
185 params: form
186 })
187 }
188 export function getExclusiveImage(id) {
189 return request({
190 url: `/system/exclusive/getExclusiveImage/${id}`,
191 method: 'get'
192 })
193 }
194 export function getScoreByUserId(id) {
195 return request({
196 url: `/system/user/getScoreByUserId`,
197 method: 'get'
198 })
199 }
200 // 图片上传
201 export function uploadImg(e) {
202 const tempFilePaths = e.tempFilePaths;
203 const imgUrl = tempFilePaths[0]
204 uni.showLoading({
205 title: '加载中'
206 });
207 return uni.uploadFile({
208 url: config.baseUrl_api + '/upload/fs',
209 header: {
210 'Authorization': uni.getStorageSync('token'),
211 },
212 filePath: imgUrl,
213 name: 'image'
214 }).then(res => {
215 let data = JSON.parse(res.data);
216 return data
217 }).finally(() => {
218 uni.hideLoading();
219 });
220 }
221
222 export function userShare(shareId) {
223 return request({
224 url: `/system/userShare/share?shareId=${shareId}`,
225 method: 'get'
226 })
227 }
228 export function getState(paperId) {
229 return request({
230 url: `/system/userAnswer/getState?paperId=${paperId}`,
231 method: 'get'
232 })
233 }
234 // 消费 充值
235 export function czList() {
236 const currUser = uni.getStorageSync('currUser')
237 return request({
238 url: `/system/pay/mylist?userId=${currUser.userId}&status=1`,
239 method: 'get'
240 })
241 }
242
243 export function xfList() {
244 const currUser = uni.getStorageSync('currUser')
245 return request({
246 url: `/system/order/mylist?userId=${currUser.userId}`,
247 method: 'get'
248 })
249 }
250
251
252
253 // 反馈页面提交
254 export function miniappData(params) {
255 return request({
256 url: `/systemj/miniappData`,
257 method: 'post',
258 params: params
259 })
260 }
261
262
263
1 int "-"?([0-9]|[1-9][0-9]+)
2 exp [eE][-+]?[0-9]+
3 frac "."[0-9]+
4
5 %%
6 \s+ /* skip whitespace */
7
8 {int}{frac}?{exp}?\b return 'NUMBER'
9 \"(?:'\\'[\\"bfnrt/]|'\\u'[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*\" yytext = yytext.substr(1,yyleng-2); return 'STRING'
10
11 "{" return '{'
12 "}" return '}'
13 "[" return '['
14 "]" return ']'
15 "," return ','
16 ":" return ':'
17 "true" return 'TRUE'
18 "false" return 'FALSE'
19 "null" return 'NULL'
20 <<EOF>> return 'EOF'
21 . return 'INVALID'
22
23 %%
1 %start JSONText
2
3 /*
4 ECMA-262 5th Edition, 15.12.1 The JSON Grammar.
5 */
6
7
8 %%
9
10 JSONString
11 : STRING
12 { // replace escaped characters with actual character
13 $$ = yytext.replace(/\\(\\|")/g, "$"+"1")
14 .replace(/\\n/g,'\n')
15 .replace(/\\r/g,'\r')
16 .replace(/\\t/g,'\t')
17 .replace(/\\v/g,'\v')
18 .replace(/\\f/g,'\f')
19 .replace(/\\b/g,'\b');
20 }
21 ;
22
23 JSONNumber
24 : NUMBER
25 {
26 //$$ = Number(yytext);
27 $$ = yytext == String(Number(yytext))? Number(yytext): yytext;
28 }
29 ;
30
31 JSONNullLiteral
32 : NULL
33 {$$ = null;}
34 ;
35
36 JSONBooleanLiteral
37 : TRUE
38 {$$ = true;}
39 | FALSE
40 {$$ = false;}
41 ;
42
43 JSONText
44 : JSONValue EOF
45 {return $$ = $1;}
46 ;
47
48 JSONValue
49 : JSONNullLiteral
50 | JSONBooleanLiteral
51 | JSONString
52 | JSONNumber
53 | JSONObject
54 | JSONArray
55 ;
56
57 JSONObject
58 : '{' '}'
59 {{$$ = {};}}
60 | '{' JSONMemberList '}'
61 {$$ = $2;}
62 ;
63
64 JSONMember
65 : JSONString ':' JSONValue
66 {$$ = [$1, $3];}
67 ;
68
69 JSONMemberList
70 : JSONMember
71 {{$$ = {}; $$[$1[0]] = $1[1];}}
72 | JSONMemberList ',' JSONMember
73 {$$ = $1; $1[$3[0]] = $3[1];}
74 ;
75
76 JSONArray
77 : '[' ']'
78 {$$ = [];}
79 | '[' JSONElementList ']'
80 {$$ = $2;}
81 ;
82
83 JSONElementList
84 : JSONValue
85 {$$ = [$1];}
86 | JSONElementList ',' JSONValue
87 {$$ = $1; $1.push($3);}
88 ;
1 import request from './request'
2 import * as api from '@/common/api.js';
3
4 const accountInfo = uni.getAccountInfoSync()
5 const appId = accountInfo.miniProgram.appId;
6
7
8 function wxLogin() {
9 return new Promise((resolve, reject) => {
10 uni.login({
11 provider: 'weixin',
12 success: (res) => {
13 // console.log(res.code);
14 resolve(res)
15 },
16 fail: (res) => {
17 reject(res)
18 }
19 })
20 })
21 }
22
23 function pcLogin(code) {
24 if (code) {
25 return pcLoginByCode(code)
26 } else {
27 const currUser = uni.getStorageSync('currUser') || {}
28 if (currUser.openId) {
29 return pcLoginByOpenId(currUser.openId);
30 } else {
31 return wxLogin().then((loginRes) => {
32 return pcLoginByCode(loginRes.code)
33 })
34 }
35 }
36 }
37
38 function repeatLogin() {
39 console.log('重新登录')
40 return wxLogin().then((loginRes) => {
41 return pcLoginByCode(loginRes.code)
42 })
43 }
44
45 function pcLoginByOpenId(openId) {
46 return request({
47 url: "/system/wx/loginByOpenId",
48 method: "POST",
49 params: {
50 appId: appId,
51 openId: openId
52 }
53 }).then((res) => {
54 let user = res.data;
55 // console.log("openId " + openId, user)
56
57 uni.setStorageSync('token', 'Bearer ' + user.token);
58 uni.setStorageSync('currUser', user);
59 return user;
60 }).catch(() => {
61 uni.removeStorageSync('currUser')
62 })
63 }
64
65 function pcLoginByCode(code) {
66 return request({
67 // url: "/weixin/api/login",
68 url: "/xcxLogin",
69 method: "POST",
70 params: {
71 appId: appId,
72 jsCode: code
73 }
74 }).then((res) => {
75 uni.setStorageSync('token', 'Bearer ' + res.data.token)
76 uni.setStorageSync('isRegister', res.data.isRegister)
77 console.log(uni.getStorageSync('isRegister'))
78 }).then(getCurrUser)
79 .catch((err) => {
80 uni.removeStorageSync('currUser')
81 })
82 }
83
84 function getCurrUser(isAuto) {
85 let token = uni.getStorageSync('token');
86 if (token) {
87 return request({
88 url: "/getInfo",
89 method: "GET",
90 opts: {
91 isAuto: isAuto
92 }
93 }).then((res) => {
94 let user = res.data.user;
95 uni.setStorageSync('currUser', user);
96 uni.setStorageSync('score', res.data.score);
97 return user
98 })
99 } else {
100 return Promise.reject()
101 }
102 }
103
104 function getWxUser() {
105 return new Promise((resolve, reject) => {
106 const currUser = uni.getStorageSync('currUser');
107 uni.getUserProfile({
108 desc: '用于完善用户信息',
109 success: function(infoRes) {
110 console.log(infoRes)
111
112 request({
113 url: `/system/wx/updateWxUser`,
114 method: "POST",
115 params: {
116 appId: appId,
117 userId: currUser.id,
118 encryptedData: infoRes.encryptedData,
119 errMsg: infoRes.errMsg,
120 iv: infoRes.iv,
121 rawData: infoRes.rawData,
122 signature: infoRes.signature
123 }
124 }).then((res) => {
125 let user = res.data;
126 uni.setStorageSync('currUser', user);
127 resolve(user);
128 }).catch(() => {
129 reject()
130 })
131 },
132 fail: (res) => {
133 reject(res)
134 }
135 });
136 });
137 }
138
139 function getWxUserPhone(phoneRes) {
140 // console.log(phoneRes)
141
142 const currUser = uni.getStorageSync('currUser');
143 return request({
144 url: `/system/wx/updateMobile`,
145 method: "POST",
146 params: {
147 appId: appId,
148 userId: currUser.id,
149 encryptedData: phoneRes.encryptedData,
150 errMsg: phoneRes.errMsg,
151 iv: phoneRes.iv,
152 rawData: phoneRes.rawData,
153 signature: phoneRes.signature
154 }
155 }).then((res) => {
156 let user = res.data;
157 uni.setStorageSync('currUser', user);
158 return user
159 })
160 }
161
162 function checkUserAuth(path) {
163 const currUser = uni.getStorageSync('currUser')
164 if (currUser.phonenumber) {
165 // if (currUser.nickName) {
166 return true
167 } else {
168 uni.navigateTo({
169 url: '/pages/index/start?path=' + encodeURIComponent(path)
170 })
171 return false;
172 }
173 }
174
175
176 export {
177 wxLogin,
178 pcLogin,
179 getCurrUser,
180 getWxUser,
181 getWxUserPhone,
182 checkUserAuth
183 }
...\ No newline at end of file ...\ No newline at end of file
1 import config from '@/config.js'
2 import {
3 pcLogin
4 } from './login'
5
6 const excludeUrls = ['/system/wx/getUserInfo']
7
8 // 获取Token
9 function getToken() {
10 try {
11 const token = uni.getStorageSync('token');
12 if (token) {
13 return token
14 } else {
15 return ''
16 }
17 } catch (e) {
18 console.log(e)
19 }
20 }
21
22 // 获取请求头
23 function getHeaders() {
24 let token = getToken()
25 let header = {
26 "Authorization": token,
27 "Content-Type": "application/json" //根据自己的数据类型
28 // "Content-Type":"application/x-www-form-urlencoded",
29 }
30 return header
31 }
32
33 let request = function(req) {
34 req.method = req.method.toUpperCase()
35 if (!['GET', 'POST', 'PUT', 'DELETE'].includes(req.method)) {
36 uni.showToast({
37 title: `暂不支持的请求方式: ${req.method}`,
38 icon: 'none'
39 });
40 return
41 }
42
43 // if (req.method == 'POST' && !req.hideLoding) {
44 // uni.showLoading({
45 // title: '提交中...'
46 // })
47 // }
48
49 return new Promise((resolve, reject) => {
50 uni.request({
51 url: config.baseUrl_api + req.url,
52 method: req.method,
53 data: req.params,
54 header: getHeaders(),
55 }).then(res => {
56 switch (res.statusCode) {
57 case 200:
58 const data = res.data || {};
59 if (data.code == 200) {
60 resolve(data)
61 } else {
62 //登录超时
63 if (data.code == 60002 || data.code == 60001) {
64 reLogin();
65 } else {
66 uni.showToast({
67 title: data.msg,
68 icon: 'none',
69 duration: 3000
70 })
71 }
72 reject(res)
73 }
74 break
75 default:
76 reject(res)
77 }
78 }).catch(res => {
79 reject(res)
80 }).finally(() => {
81 // if (req.method == 'POST' && !req.hideLoding) {
82 // uni.hideLoading()
83 // }
84 })
85 })
86 }
87
88 function reLogin() {
89 const currUser = uni.getStorageSync('currUser') || {}
90 if (currUser.openId) {
91 const accountInfo = uni.getAccountInfoSync()
92 pcLoginByOpenId(accountInfo.miniProgram.appId, currUser.openId)
93 .then((res) => {
94 let user = res.data;
95 uni.setStorageSync('token', user.token);
96 uni.setStorageSync('currUser', user);
97
98 uni.showToast({
99 title: '一走神把您的操作遗漏了,请重试',
100 icon: 'none'
101 })
102 }).catch(() => {
103 uni.showToast({
104 title: '服务异常,请稍后重试',
105 icon: 'none'
106 })
107 })
108 }
109 }
110
111 function pcLoginByOpenId(appId, openId) {
112 return request({
113 url: "/system/wx/loginByOpenId",
114 method: "POST",
115 params: {
116 appId: appId,
117 openId: openId
118 }
119 })
120 }
121
122
123 export default request;
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view class="content">
3 <swiper class="swiper"
4 :autoplay="autoplay"
5 :duration="duration">
6 <swiper-item>
7 <view class="swiper-item">
8 <view class="swiper-item-img"><image src="../../static/guide/title_01.png" mode="aspectFit"></image></view>
9 <view class="swiper-item-img"><image src="../../static/guide/icon_01.png" mode="aspectFit"></image></view>
10 </view>
11 <view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
12 </swiper-item>
13 <swiper-item>
14 <view class="swiper-item">
15 <view class="swiper-item-img"><image src="../../static/guide/title_02.png" mode="aspectFit"></image></view>
16 <view class="swiper-item-img"><image src="../../static/guide/icon_02.png" mode="aspectFit"></image></view>
17 </view>
18 <view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
19 </swiper-item>
20 <swiper-item>
21 <view class="swiper-item">
22 <view class="swiper-item-img"><image src="../../static/guide/title_03.png" mode="aspectFit"></image></view>
23 <view class="swiper-item-img"><image src="../../static/guide/icon_03.png" mode="aspectFit"></image></view>
24 </view>
25 <view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
26 </swiper-item>
27 <swiper-item>
28 <view class="swiper-item">
29 <view class="swiper-item-img"><image src="../../static/guide/title_04.png" mode="aspectFit"></image></view>
30 <view class="swiper-item-img"><image src="../../static/guide/icon_04.png" mode="aspectFit"></image></view>
31 </view>
32 <view class="experience" @tap="launchFlag()">{{experience}}</view>
33 </swiper-item>
34 </swiper>
35 <view class="uniapp-img"><image src="../../static/guide/uniapp4@2x.png" mode="aspectFit"></image></view>
36 </view>
37 </template>
38
39 <script>
40 export default {
41 data() {
42 return {
43 background: ['color1', 'color2', 'color3'],
44 autoplay: false,
45 duration: 500,
46 jumpover: '跳过',
47 experience: '立即体验'
48 }
49 },
50 methods: {
51 launchFlag: function(){
52 /**
53 * 向本地存储中设置launchFlag的值,即启动标识;
54 */
55 uni.setStorage({
56 key: 'launchFlag',
57 data: true,
58 });
59 uni.switchTab({
60 url: '/pages/tabBar/component/component'
61 });
62
63 }
64 }
65 }
66 </script>
67 <style>
68 page,
69 .content{
70 width: 100%;
71 height: 100%;
72 background-size: 100% auto ;
73 padding: 0;
74 }
75 .swiper{
76 width: 100%;
77 height: 80%;
78 background: #FFFFFF;
79 }
80 .swiper-item {
81 width: 100%;
82 height: 100%;
83 text-align: center;
84 position: relative;
85 display: flex;
86 /* justify-content: center; */
87 align-items:flex-end;
88 flex-direction:column-reverse
89 }
90 .swiper-item-img{
91 width: 100%;
92 height: auto;
93 margin: 0 auto;
94 }
95 .swiper-item-img image{
96 width: 80%;
97 }
98 .uniapp-img{
99 height: 20%;
100 background: #FFFFFF;
101 display: flex;
102 justify-content: center;
103 align-items:center;
104 overflow: hidden;
105 }
106 .uniapp-img image{
107 width: 40%;
108 }
109
110 .jump-over,.experience{
111 position: absolute;
112 height: 60upx;
113 line-height: 60upx;
114 padding: 0 40upx;
115 border-radius: 30upx;
116 font-size: 32upx;
117 color: #454343;
118 border: 1px solid #454343;
119 z-index: 999;
120 }
121 .jump-over{
122 right: 45upx;
123 top: 125upx;
124 }
125 .experience{
126 right: 50%;
127 margin-right: -105upx;
128 bottom: 0;
129 }
130 </style>
1 # 引导页
2
3 ### 基于uni-app框架的swiper组件打开的时候启动。
4
5 > 首次启动展示引导页,之后启动不再展示。那么就意味着,我们需要一个标识来确定,App是否已经启动过。
6
7 > 我们可以在本地存储一个key来做为已经启动过App的标识。那么,我们在入口这里,就可以读取这个key,来决定是否展示引导页。
8
9 > 因工作繁忙目前该程序金对安卓做了适配,IOS可根据环境自己适配。谢谢
10
11 ## 目录结构
12 * /pages/index/index.vue //入口页
13 ### 存储key
14 * 向本地存储中设置launchFlag的值,即启动标识;
15 ### 获取key
16 * 向本地存储中设置launchFlag的值,即启动标识;
17 * 获取本地存储中launchFlag的值
18 * 若存在,说明不是首次启动,直接进入首页;
19 * 若不存在,说明是首次启动,进入引导页;
20
21 ```html
22 <view class="main">
23 <code-elf-guide v-if="guidePages"></code-elf-guide>
24 </view>
25
26 ```
27
28 ```javascript
29 import codeElfGuide from '@/components/code-elf-guide/code-elf-guide.vue'
30 export default {
31 components: {
32 codeElfGuide
33 },
34 data() {
35 return {
36 guidePages:true
37 }
38 },
39 onLoad(){
40 this.loadExecution()
41 },
42 methods: {
43 loadExecution: function(){
44 /**
45 * 获取本地存储中launchFlag的值
46 * 若存在,说明不是首次启动,直接进入首页;
47 * 若不存在,说明是首次启动,进入引导页;
48 */
49 try {
50 // 获取本地存储中launchFlag标识
51 const value = uni.getStorageSync('launchFlag');
52 if (value) {
53 // launchFlag=true直接跳转到首页
54 uni.switchTab({
55 url: '/pages/tabBar/component/component'
56 });
57 } else {
58 // launchFlag!=true显示引导页
59 this.guidePages = true
60 }
61 } catch(e) {
62 // error
63 uni.setStorage({
64 key: 'launchFlag',
65 data: true,
66 success: function () {
67 console.log('error时存储launchFlag');
68 }
69 });
70 this.guidePages = true
71 }
72 }
73 }
74 }
75 ```
76 ```css
77 page,.main{
78 width: 100%;
79 height: 100%;
80 }
81
82 ```
83
84 ### 首页清除key,进行测试
85 * 清除本地存储中设置launchFlag的值,即启动标识;
86 * 两秒后重启APP,进行测试
87 ```javascript
88 uni.showModal({
89 title: '清除launchFlag值',
90 content: '确定要清除launchFlag值,进行重启测试?',
91 success: function (res) {
92 if (res.confirm) {
93 console.log('用户点击确定');
94 // 清除缓存
95 uni.clearStorage();
96 uni.showToast({
97 icon: 'none',
98 duration:3000,
99 title: '清除成功2秒后重启'
100 });
101 // 两秒后重启
102 setTimeout(function() {
103 uni.hideToast();
104 plus.runtime.restart();
105 }, 2000);
106 } else if (res.cancel) {
107 console.log('用户点击取消');
108 }
109 }
110 });
111 ```
...\ No newline at end of file ...\ No newline at end of file
1 # slider-range
2 uni-app 滑块区间选择组件
3
4 可根据具体需求,修改、自定义其他内容。
5
6 ## 属性说明
7
8 |属性名|类型|默认值|说明|
9 | -- | -- | --|--|
10 | value | Array<Number, Number> | [0,100] |滑块已选中区间的值|
11 | min | Number| 0 | 滑块区间最小值 |
12 | max | Number | 100 | 滑块区间最大值 |
13 | step | Number | 1 | 拖动时的步长 |
14 | disabled | Boolean | false | 是否为禁用状态 |
15 | height | Number | 50 | 滑块容器高度 |
16 | barHeight | Number | 5 | 滑块进度条高度 |
17 | backgroundColor | String | #e9e9e9| 滑块进度条背景色|
18 | activeColor | String | #1aad19 | 已选中区间进度条颜色|
19 | blockSize | Number | 20 | 滑块大小 |
20 | blockColor | String | #fff | 滑块颜色 |
21 | decorationVisible | Boolean | false | 是否显示滑块内装饰元素|
22 | tipVisible | Boolean | true | 是否显示滑块值提示文本 |
23 | fomat| Function | | 滑块值提示文本格式化函数,**注意**:小程序中此属性必传,否则会报错,如果无需格式化,可以简单返回原始值: `format(val) { return val }`;H5中可以不传。|
24
25
26 ## 使用示例
27
28 ```html
29
30 <slider-range
31 :value="rangeValue"
32 :min="rangeMin"
33 :max="rangMax"
34 :step="5"
35 :bar-height="3"
36 :block-size="26"
37 background-color="#EEEEF6"
38 active-color="#FF6B00"
39 :format="format"
40 :decorationVisible="true"
41 @change="handleRangeChange"
42 ></slider-range>
43
44
45 ```
46
47 ```javascript
48
49 import SliderRange from '../components/slider-range/index.vue'
50 export default {
51 components: {
52 SliderRange
53 },
54 data() {
55 return {
56 rangeMin: 5,
57 rangMax: 200,
58 rangeValue: [10, 50]
59 }
60 },
61 methods: {
62 format(val) {
63 return val + '%'
64 },
65 handleRangeChange(e) {
66 this.rangeValue = e
67 }
68 }
69 }
70 ```
71
72 效果图
73
74 ![](http://images.alisali.cn/img_20190715175325.png)
1 <template>
2 <view
3 class="slider-range"
4 :class="{ disabled: disabled }"
5 :style="{ paddingLeft: blockSize / 2 + 'px', paddingRight: blockSize / 2 + 'px' }"
6 >
7 <view class="slider-range-inner" :style="{ height: height + 'px' }">
8 <view
9 class="slider-bar"
10 :style="{
11 height: barHeight + 'px',
12 }"
13 >
14 <!-- 背景条 -->
15 <view
16 class="slider-bar-bg"
17 :style="{
18 backgroundColor: backgroundColor,
19 }"
20 ></view>
21
22 <!-- 滑块实际区间 -->
23 <view
24 class="slider-bar-inner"
25 :style="{
26 width: ((values[1] - values[0]) / (max - min)) * 100 + '%',
27 left: lowerHandlePosition + '%',
28 backgroundColor: activeColor,
29 }"
30 ></view>
31 </view>
32
33 <!-- 滑动块-左 -->
34 <view
35 class="slider-handle-block"
36 :class="{ decoration: decorationVisible }"
37 :style="{
38 backgroundColor: blockColor,
39 width: blockSize + 'px',
40 height: blockSize + 'px',
41 left: lowerHandlePosition + '%',
42 }"
43 @touchstart="_onTouchStart"
44 @touchmove="_onBlockTouchMove"
45 @touchend="_onBlockTouchEnd"
46 data-tag="lowerBlock"
47 ></view>
48
49 <!-- 滑动块-右 -->
50 <view
51 class="slider-handle-block"
52 :class="{ decoration: decorationVisible }"
53 :style="{
54 backgroundColor: blockColor,
55 width: blockSize + 'px',
56 height: blockSize + 'px',
57 left: higherHandlePosition + '%',
58 }"
59 @touchstart="_onTouchStart"
60 @touchmove="_onBlockTouchMove"
61 @touchend="_onBlockTouchEnd"
62 data-tag="higherBlock"
63 ></view>
64
65 <!-- 滑块值提示 -->
66 <view v-if="tipVisible" class="range-tip" :style="lowerTipStyle">{{ format(values[0]) }}</view>
67 <view v-if="tipVisible" class="range-tip" :style="higherTipStyle">{{ format(values[1]) }}</view>
68 </view>
69 </view>
70 </template>
71 <script>
72 export default {
73 components: {},
74 props: {
75 //滑块区间当前取值
76 value: {
77 type: Array,
78 default: function() {
79 return [0, 100]
80 },
81 },
82 //最小值
83 min: {
84 type: Number,
85 default: 0,
86 },
87 //最大值
88 max: {
89 type: Number,
90 default: 100,
91 },
92 step: {
93 type: Number,
94 default: 1,
95 },
96 format: {
97 type: Function,
98 default: function(val) {
99 return val
100 },
101 },
102 disabled: {
103 type: Boolean,
104 default: false,
105 },
106 //滑块容器高度
107 height: {
108 height: Number,
109 default: 50,
110 },
111 //区间进度条高度
112 barHeight: {
113 type: Number,
114 default: 5,
115 },
116 //背景条颜色
117 backgroundColor: {
118 type: String,
119 default: '#e9e9e9',
120 },
121 //已选择的颜色
122 activeColor: {
123 type: String,
124 default: '#1aad19',
125 },
126 //滑块大小
127 blockSize: {
128 type: Number,
129 default: 20,
130 },
131 blockColor: {
132 type: String,
133 default: '#fff',
134 },
135 tipVisible: {
136 type: Boolean,
137 default: true,
138 },
139 decorationVisible: {
140 type: Boolean,
141 default: false,
142 },
143 },
144 data() {
145 return {
146 values: [this.min, this.max],
147 startDragPos: 0, // 开始拖动时的坐标位置
148 startVal: 0, //开始拖动时较小点的值
149 }
150 },
151 computed: {
152 // 较小点滑块的坐标
153 lowerHandlePosition() {
154 return ((this.values[0] - this.min) / (this.max - this.min)) * 100
155 },
156 // 较大点滑块的坐标
157 higherHandlePosition() {
158 return ((this.values[1] - this.min) / (this.max - this.min)) * 100
159 },
160 lowerTipStyle() {
161 if (this.lowerHandlePosition < 90) {
162 return `left: ${this.lowerHandlePosition}%;`
163 }
164 return `right: ${100 - this.lowerHandlePosition}%;transform: translate(50%, -100%);`
165 },
166 higherTipStyle() {
167 if (this.higherHandlePosition < 90) {
168 return `left: ${this.higherHandlePosition}%;`
169 }
170 return `right: ${100 - this.higherHandlePosition}%;transform: translate(50%, -100%);`
171 },
172 },
173 created: function() {},
174 onLoad: function(option) {},
175 watch: {
176 //滑块当前值
177 value: {
178 immediate: true,
179 handler(newVal, oldVal) {
180 if (this._isValuesValid(newVal) && (newVal[0] !== this.values[0] || newVal[1] !== this.values[1])) {
181 this._updateValue(newVal)
182 }
183 },
184 },
185 },
186 methods: {
187 _updateValue(newVal) {
188 // 步长大于区间差,或者区间最大值和最小值相等情况
189 if (this.step >= this.max - this.min) {
190 throw new RangeError('Invalid slider step or slider range')
191 }
192
193 let newValues = []
194 if (Array.isArray(newVal)) {
195 newValues = [newVal[0], newVal[1]]
196 }
197 if (typeof newValues[0] !== 'number') {
198 newValues[0] = this.values[0]
199 } else {
200 newValues[0] = Math.round((newValues[0] - this.min) / this.step) * this.step + this.min
201 }
202 if (typeof newValues[1] !== 'number') {
203 newValues[1] = this.values[1]
204 } else {
205 newValues[1] = Math.round((newValues[1] - this.min) / this.step) * this.step + this.min
206 }
207
208 // 新值与原值相等,不做处理
209 if (this.values[0] === newValues[0] && this.values[1] === newValues[1]) {
210 return
211 }
212 // 左侧滑块值小于最小值时,设置为最小值
213 if (newValues[0] < this.min) {
214 newValues[0] = this.min
215 }
216 // 右侧滑块值大于最大值时,设置为最大值
217 if (newValues[1] > this.max) {
218 newValues[1] = this.max
219 }
220 // 两个滑块重叠或左右交错,使两个滑块保持最小步长的间距
221 if (newValues[0] >= newValues[1]) {
222 // 左侧未动,右侧滑块滑到左侧滑块之左
223 if (newValues[0] === this.values[0]) {
224 newValues[1] = newValues[0] + this.step
225 } else {
226 // 右侧未动, 左侧滑块滑到右侧之右
227 newValues[0] = newValues[1] - this.step
228 }
229 }
230
231 this.values = newValues
232 this.$emit('change', this.values)
233 },
234 _onTouchStart: function(event) {
235 if (this.disabled) {
236 return
237 }
238
239 this.isDragging = true
240 let tag = event.target.dataset.tag
241
242 //兼容h5平台及某版本微信
243 let e = event.changedTouches ? event.changedTouches[0] : event
244 this.startDragPos = e.pageX
245
246 this.startVal = tag === 'lowerBlock' ? this.values[0] : this.values[1]
247 },
248 _onBlockTouchMove: function(e) {
249 if (this.disabled) {
250 return
251 }
252 this._onDrag(e)
253 },
254 _onBlockTouchEnd: function(e) {
255 if (this.disabled) {
256 return
257 }
258 this.isDragging = false
259 this._onDrag(e)
260 },
261 _onDrag(event) {
262 if (!this.isDragging) {
263 return
264 }
265 let view = uni
266 .createSelectorQuery()
267 .in(this)
268 .select('.slider-range-inner')
269
270 view
271 .boundingClientRect(data => {
272 let sliderWidth = data.width
273 const tag = event.target.dataset.tag
274 let e = event.changedTouches ? event.changedTouches[0] : event
275 let diff = ((e.pageX - this.startDragPos) / sliderWidth) * (this.max - this.min)
276 let nextVal = this.startVal + diff
277
278 if (tag === 'lowerBlock') {
279 this._updateValue([nextVal, null])
280 } else {
281 this._updateValue([null, nextVal])
282 }
283 })
284 .exec()
285 },
286 _isValuesValid: function(values) {
287 return Array.isArray(values) && values.length == 2
288 },
289 },
290 }
291 </script>
292
293 <style scoped>
294 .slider-range {
295 position: relative;
296 padding-top: 40rpx;
297 }
298
299 .slider-range-inner {
300 position: relative;
301 width: 100%;
302 }
303
304 .slider-range.disabled .slider-bar-inner {
305 opacity: 0.35;
306 }
307
308 .slider-range.disabled .slider-handle-block {
309 cursor: not-allowed;
310 }
311
312 .slider-bar {
313 position: absolute;
314 top: 50%;
315 left: 0;
316 right: 0;
317 transform: translateY(-50%);
318 }
319
320 .slider-bar-bg {
321 position: absolute;
322 width: 100%;
323 height: 100%;
324 border-radius: 10000px;
325 z-index: 10;
326 }
327
328 .slider-bar-inner {
329 position: absolute;
330 width: 100%;
331 height: 100%;
332 border-radius: 10000px;
333 z-index: 11;
334 }
335
336 .slider-handle-block {
337 position: absolute;
338 top: 50%;
339 transform: translate(-50%, -50%);
340 border-radius: 50%;
341 box-shadow: 0 0 3px 2px rgba(227, 229, 241, 0.5);
342 z-index: 12;
343 }
344
345 .slider-handle-block.decoration::before {
346 position: absolute;
347 content: '';
348 width: 6upx;
349 height: 24upx;
350 top: 50%;
351 left: 29%;
352 transform: translateY(-50%);
353 background: #eeedf2;
354 border-radius: 3upx;
355 z-index: 13;
356 }
357
358 .slider-handle-block.decoration::after {
359 position: absolute;
360 content: '';
361 width: 6upx;
362 height: 24upx;
363 top: 50%;
364 right: 29%;
365 transform: translateY(-50%);
366 background: #eeedf2;
367 border-radius: 3upx;
368 z-index: 13;
369 }
370
371 .range-tip {
372 position: absolute;
373 top: 0;
374 font-size: 24upx;
375 color: #666;
376 transform: translate(-50%, -100%);
377 }
378 </style>
1 <template>
2 <view class="demo-slider-range">
3 <view class="section-title">普通用法</view>
4 <view class="slider-item">
5 <slider-range
6 :value="slider1.rangeValue"
7 :min="slider1.min"
8 :max="slider1.max"
9 :step="slider1.step"
10 :bar-height="barHeight"
11 :block-size="blockSize"
12 :background-color="backgroundColor"
13 :format="format1"
14 @change="handleRangeChange"
15 ></slider-range>
16 </view>
17 <view class="section-title">自定义</view>
18 <view class="slider-item">
19 <slider-range
20 :value="slider2.rangeValue"
21 :min="slider2.min"
22 :max="slider2.max"
23 :step="slider2.step"
24 :bar-height="barHeight"
25 :block-size="blockSize"
26 :background-color="backgroundColor"
27 :active-color="slider2.activeColor"
28 :format="format2"
29 :decorationVisible="slider2.decorationVisible"
30 @change="handleRangeChange"
31 ></slider-range>
32 </view>
33 </view>
34 </template>
35
36 <script>
37 import SliderRange from '../../components/slider-range/index.vue'
38 export default {
39 components: {
40 SliderRange,
41 },
42 data() {
43 return {
44 barHeight: 3,
45 blockSize: 26,
46 backgroundColor: '#EEEEF6',
47 slider1: {
48 min: 50,
49 max: 200,
50 step: 10,
51 rangeValue: [50, 150],
52 },
53 slider2: {
54 rangeMin: 0,
55 rangMax: 100,
56 rangeValue: [8, 80],
57 step: 1,
58 activeColor: '#FF6B00',
59 decorationVisible: true,
60 },
61 }
62 },
63 methods: {
64 format1(val) {
65 return val
66 },
67 format2(val) {
68 return `${val}%`
69 },
70 handleRangeChange(e) {
71 this.rangeValue = e
72 },
73 },
74 }
75 </script>
76 <style>
77 .demo-slider-range {
78 background-color: #fff;
79 padding: 100rpx 40rpx 0;
80 }
81
82 .section-title {
83 padding: 0 0 20rpx;
84 color: #666;
85 }
86
87 .slider-item:not(:last-child) {
88 margin-bottom: 100rpx;
89 }
90 </style>
1 // prod
2 // const baseUrl = 'https://research.wtwuxicenter.com/';
3 // const baseUrl_api=`${baseUrl}/prod-api`;
4
5 // uat
6 // const baseUrl = 'https://jxt.itechtop.cn';
7 // const baseUrl_api = `${baseUrl}/prod-api`;
8
9 // staging
10 // const baseUrl = "http://192.168.1.118:5599"
11 // const baseUrl = "https://xtavqfekqb5r.guyubao.com"
12 const baseUrl = "https://ceping.itechtop.cn/stage-api";
13 const baseUrl_api = `${baseUrl}`;
14
15 const fileUrl = "http://r.itechtop.cn";
16
17 export default {
18 baseUrl: baseUrl,
19 fileUrl: fileUrl,
20 baseUrl_api: baseUrl_api,
21 }
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view class="whitebg">
4 <image class="ccover" mode="aspectFit" :src="config.baseUrl_api+form.activityPic"></image>
5
6 <view class="name">{{form.activityName}}
7 <view v-if="isBuy" style="font-size: 32rpx;color: #1EC886;display: inline-block;float: right;">
8 <uni-icons color="#1EC886" size="22" type="checkbox-filled"></uni-icons>已报名
9 </view>
10
11 </view>
12
13 <view class="text-warning pp" v-if="form.isFree==1">
14 <text v-if="form.allGold>0">金币{{form.allGold}}</text>
15 <text v-if="form.allGold>0&&form.allScore>0">/</text>
16 <text v-if="form.allScore>0">积分{{form.allScore}}</text>
17 <text v-if="form.gold>0">/金币{{form.gold}}+积分{{form.score}}</text>
18 </view>
19 <view v-else class="text-warning pp">免费</view>
20 <view class="pp">活动时间:{{form.startTime}}{{form.endTime}}</view>
21 <view class="pp">活动地址:{{form.address}}</view>
22 </view>
23
24 <view class="plane">
25 <view class="phead">
26 <view>
27 <image class="tag01" src="@/course/img/tag01.png" style="width:30rpx;height: 30rpx;"></image>
28 活动介绍
29 </view>
30 <view class="text-warning">讲师:{{form.speaker}}</view>
31 </view>
32 <view class="pbody">
33 {{form.description}}
34 </view>
35 </view>
36
37 <view style="height: 100rpx;"></view>
38 <view class="fixedBottom">
39 <button class="btn btn-submit" v-if="isBuy">已报名</button>
40 <button class="btn btn-submit" v-else @click="goBill">立即报名</button>
41 </view>
42 </view>
43 </template>
44
45 <script setup>
46 import {
47 onLoad,
48 onShow
49 } from '@dcloudio/uni-app';
50 import config from '@/config.js';
51 import {
52 ref,
53 getCurrentInstance
54 } from 'vue';
55 import * as api from '@/common/api.js';
56
57 const form = ref({})
58 const isBuy = ref(false)
59 let goodsId
60 onLoad((option) => {
61 uni.showLoading({
62 title: '加载中'
63 })
64 if (option.id) {
65 goodsId = option.id
66 }
67 })
68 onShow(() => {
69 if (goodsId)
70 getData(goodsId)
71 })
72
73 function getData(id) {
74 api.getActiveById(id).then(res => {
75 form.value = res.data
76 uni.hideLoading()
77 api.getUserIsPay({
78 orderType: 1,
79 goodsId: goodsId
80 }).then(Response => {
81 isBuy.value = Response.data
82 })
83
84 })
85 }
86
87 function goBill() {
88 if(form.value.isFree=='1'){
89 const obj = encodeURIComponent(JSON.stringify(form.value))
90 let path = `/course/courseBill?form=${obj}`
91 uni.navigateTo({
92 url: path
93 });
94
95 } else {
96 api.submitOrder({
97 orderType: 1,
98 goodsId: form.value.activityId,
99 payType: "0"
100 }).then(res => {
101 uni.showModal({
102 content:'报名成功!',
103 success:function(respons){
104 if(respons.confirm){
105 getData(goodsId)
106 }
107 }
108 })
109 })
110 }
111 }
112 </script>
113
114 <style scoped lang="scss">
115 .whitebg {
116 background: #fff;
117 padding: 25rpx;
118 }
119
120 .plane {
121 background: #fff;
122 width: 700rpx;
123 border-radius: 15rpx;
124 margin: 30rpx auto;
125 padding: 25rpx;
126 box-sizing: border-box;
127
128 .phead {
129 border-bottom: 1rpx solid #eee;
130 display: flex;
131 justify-content: space-between;
132 padding: 0 0 15rpx;
133 align-items: center;
134 font-size: 30rpx;
135 box-sizing: border-box;
136
137 .text-warning {
138 font-size: 28rpx;
139 }
140
141 .tag01 {}
142 }
143
144 .pbody {
145 padding: 15rpx 0;
146 box-sizing: border-box;
147 line-height: 40rpx;
148 font-size: 28rpx;
149 color: #4C5359;
150 }
151 }
152
153 .wList {
154 background: #fff;
155 padding: 36rpx 23rpx;
156 box-sizing: border-box;
157 border-radius: 15rpx;
158 width: 700rpx;
159 margin: 0 auto 30rpx;
160 position: relative;
161
162 .pp {
163 display: flex;
164 color: #8F8E94;
165 font-size: 24rpx;
166 align-items: center;
167
168 image {
169 margin-right: 6rpx;
170 }
171 }
172
173 .name {
174 color: #2B3133;
175 font-size: 30rpx;
176 margin: 15rpx 0 0;
177 }
178
179 .playBtn {
180 position: absolute;
181 right: 24rpx;
182 top: 0;
183 bottom: 0;
184 margin: auto;
185 height: 48rpx;
186 }
187 }
188
189 .ccover {
190 width: 700rpx;
191 margin: 0 auto 30rpx;
192 display: block;
193 height: 320rpx;
194 border-radius: 15rpx;
195 }
196
197 .whitebg {
198 .name {
199 font-size: 32rpx;
200 }
201
202 .pp {
203 color: #8F8E94;
204 font-size: 26rpx;
205 margin: 10rpx 0 0;
206 }
207
208 .text-warning {
209 color: #F39800;
210 }
211 }
212 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view class="list">
4 <view class="kcitem">
5 <image v-if="form.coursePic" :src="config.baseUrl_api+form.coursePic" mode="aspectFill"></image>
6 <image v-if="form.activityPic" :src="config.baseUrl_api+form.activityPic" mode="aspectFill"></image>
7 <view class="info">
8 <view class="tt esp_2" v-if="form.courseName">{{form.courseName}}</view>
9 <view class="tt esp_2" v-if="form.activityName">{{form.activityName}}</view>
10 <!-- <view class="pp"><uni-icons type="chatboxes" size="12" />209w 学习</view> -->
11 <!-- <view class="text-warning">{{form.explains}}</view> -->
12 </view>
13 </view>
14 </view>
15 <view class="rrcard">
16 <view class="t" v-if="system!='iPhone'&&system!='iPad'">支付方式</view>
17 <view class="t" v-else>兑换方式</view>
18 <view class="whitebg">
19 <radio-group @change="payChange">
20 <label class="uni-list-cell uni-list-cell-pd" v-if="form.allScore>0">
21 <view class="littleimgBox">
22 {{form.allScore}} 积分
23 </view>
24 <view>
25 <radio checked="checked" value="0" />
26 </view>
27 </label>
28 <label class="uni-list-cell uni-list-cell-pd" v-if="form.allGold>0&&system!='iPhone'&&system!='iPad'">
29 <view class="littleimgBox">
30 {{form.allGold}} 金币
31 </view>
32 <view>
33 <radio value="1" />
34 </view>
35 </label>
36
37 <label class="uni-list-cell uni-list-cell-pd" v-if="form.gold>0&&form.score>0&&system!='iPhone'&&system!='iPad'">
38 <view class="littleimgBox">
39 {{form.gold}} 金币 + {{form.score}} 积分
40 </view>
41 <view>
42 <radio value="2" />
43 </view>
44 </label>
45 </radio-group>
46 </view>
47 </view>
48 <view class="rrcard mt-30" v-if="form.sale">
49 <view class="t">可支持的优惠</view>
50 <view class="whitebg">
51 <radio-group>
52 <label class="uni-list-cell uni-list-cell-pd">
53 <view class="littleimgBox text-warning">
54 VIP会员
55 <text>{{form.sale/10}}</text>
56
57 </view>
58 <view v-if="system!='iPhone'&&system!='iPad'">
59 <radio v-if="mm.memType=='1'" checked="checked"/>
60 <view v-else @click="beVip">成为VIP 享受此优惠></view>
61 </view>
62 </label>
63 </radio-group>
64 </view>
65
66 </view>
67 <view class="rrcard mt-30">
68 <view class="t">我的余额</view>
69 <view class="whitebg">
70 <label class="uni-list-cell uni-list-cell-pd">
71 <view class="littleimgBox">
72 金币:{{mm.gold||0}}
73 </view>
74
75 <view style="color: #999;" v-if="system!='iPhone'&&system!='iPad'" @click="goPath('/usercenter/mycard/renew')">去充值></view>
76 </label>
77 <label class="uni-list-cell uni-list-cell-pd">
78 <view class="littleimgBox">
79 积分:{{mm.score||0}}
80 </view>
81 <view>
82
83 </view>
84 </label>
85 </view>
86 <view class="explains" v-if="form.explains">{{form.explains}}</view>
87 </view>
88 <view class="fixedBottom">
89 <view class="flexbox">
90 <view>
91 <view class="text-warning" v-if="mm.memType=='1'">
92 <text v-if="form.payType==1">{{form.allGold*form.sale/100}} 金币</text>
93 <text v-if="form.payType==0">{{form.allScore*form.sale/100}} 积分</text>
94 <text v-if="form.payType==2">{{form.gold*form.sale/100}} 金币 + {{form.score*form.sale/100}} 积分</text>
95 </view>
96 <view class="text-del" v-if="mm.memType=='1'">
97 <text v-if="form.payType==1">{{form.allGold}} 金币</text>
98 <text v-if="form.payType==0">{{form.allScore}} 积分</text>
99 <text v-if="form.payType==2">{{form.gold}} 金币 + {{form.score}} 积分</text>
100 </view>
101 <view class="text-warning" v-else>
102 <text v-if="form.payType==1">{{form.allGold}} 金币</text>
103 <text v-if="form.payType==0">{{form.allScore}} 积分</text>
104 <text v-if="form.payType==2">{{form.gold}} 金币 + {{form.score}} 积分</text>
105 </view>
106 </view>
107 <view v-if="system!='iPhone'&&system!='iPad'">
108 <button class="btn btn-submit" v-if="orderType==0" @click="pay">确定购买</button>
109 <button class="btn btn-submit" v-else @click="pay">确定报名</button>
110 </view>
111 <view v-else>
112 <button class="btn btn-submit" @click="pay">立即兑换</button>
113 </view>
114 </view>
115 </view>
116
117 <uni-popup ref="vippay" type="center">
118 <view style="position: relative;">
119 <image src="@/usercenter/img/popup2.png" style="width: 620rpx;height: 568rpx;"></image>
120 <view class="bigPrice">{{vipPrice}}</view>
121 <button class="btn btn-submit priceBtn" style="width: 400rpx;" @click="payVip">
122 立即支付 ¥{{vipPrice}}/年</button>
123 </view>
124 </uni-popup>
125
126 </view>
127 </template>
128
129 <script setup>
130 import {
131 onLoad,
132 onShow,onReady
133 } from '@dcloudio/uni-app';
134 import config from '@/config.js';
135 import {
136 ref,
137 getCurrentInstance
138 } from 'vue';
139 import * as api from '@/common/api.js';
140 const form = ref({})
141 const mm = ref({})
142 const orderType = ref(0)
143 const vipPrice = ref(0)
144 const vippay = ref(null)
145 const system = uni.getStorageSync('systemType')
146 onLoad((option) => {
147 if ('form' in option) {
148 form.value = JSON.parse(decodeURIComponent(option.form))
149 if (form.value.courseId) {
150 orderType.value = 0
151 } else {
152 orderType.value = 1
153 }
154 }
155 getUserExt()
156 })
157 onReady(() => {
158 if (orderType.value = 1) {
159 uni.setNavigationBarTitle({
160 title: '活动兑换'
161 });
162 } else {
163 uni.setNavigationBarTitle({
164 title: '课程兑换'
165 });
166 }
167 })
168 function getUserExt(){
169 api.getUserExtByUserId().then(res=>{
170 mm.value = res.data
171 })
172 }
173 function payChange(e) {
174 console.log(e.detail.value)
175 form.value.payType = e.detail.value
176 }
177
178 function pay() {
179 console.log(form.value.payType,mm.value.gold,mm.value.score)
180 if(form.value.payType==1&&(form.value.allGold>mm.value.gold)){
181 let msg = '去充值'
182 uni.showModal({
183 content: '金币不足',
184 confirmText: msg,
185 success:function(res){
186 if(res.confirm){
187 goPath('/usercenter/mycard/renew')
188 }
189 }
190 })
191 return
192 }
193 if(form.value.payType==0&&(form.value.allScore>mm.value.score)){
194 uni.showModal({
195 content: '积分不足',
196 success:function(res){
197 if(res.confirm){
198
199 }
200 }
201 })
202 return
203 }
204 if(form.value.payType==2&&(form.value.score>mm.value.score||form.value.gold>mm.value.gold)){
205 uni.showModal({
206 content: '余额不足',
207 confirmText:'去充值',
208 success:function(res){
209 if(res.confirm){
210 goPath('/usercenter/mycard/renew')
211 }
212 }
213 })
214 return
215 }
216
217 var obj = {}
218 if (orderType.value == 0) {
219 obj = {
220 orderType: 0,
221 goodsId: form.value.courseId,
222 payType: form.value.payType
223 }
224 } else {
225 obj = {
226 orderType: 1,
227 goodsId: form.value.activityId,
228 payType: form.value.payType
229 }
230 }
231 uni.showModal({
232 content:'确定购买吗',
233 success:function(resp){
234 if(resp.confirm){
235 api.submitOrder(obj).then(res => {
236 console.log(res)
237
238 if(res.data == -100){
239 uni.showToast({
240 title: '余额不足',
241 icon:'none'
242 })
243 } else {
244 uni.showToast({
245 title: '操作成功'
246 })
247 uni.navigateBack()
248 }
249 })
250 }
251 }
252 })
253
254
255 }
256 function goPath(path) {
257 uni.navigateTo({
258 url: path
259 });
260 }
261 function beVip(){
262 api.getVipPrice().then(res => {
263 vipPrice.value = res.msg
264 vippay.value.open()
265 })
266 }
267 function payVip() {
268 api.createOrder({
269 total: vipPrice.value,
270 payType: 0
271 }).then(res => {
272 const openId = currUser.openId
273 // const openId = 'oRufa4ifoP2I3hnoLAwoAreKkppA'
274 api.payForOrder({
275 payId: res.data.payId,
276 openId: openId
277 }).then(Response => {
278 // wePay(Response.data.weixinData)
279 })
280 })
281 }
282
283 function wePay(configdata) {
284 console.log(configdata)
285 // 微信支付
286 uni.requestPayment({
287 "provider": "wxpay",
288 "appId": configdata.appId,
289 "nonceStr": configdata.nonceStr,
290 "package": configdata.packageValue, // 随机字符串
291 "timeStamp": configdata.timeStamp, // 时间戳(单位:秒)
292 "signType": configdata.signType, // 签名,这里用的 MD5/RSA 签名
293 "paySign": configdata.paySign,
294 success(res) {
295 console.log(res)
296 uni.showModal({
297 content: '支付成功',
298 success: function(resp) {
299 if (resp.confirm) {
300 init()
301 }
302 }
303 })
304 },
305 fail(e) {
306 console.log(e)
307 uni.showToast({
308 title: '支付取消',
309 icon: 'none'
310 });
311 }
312 })
313 }
314
315 </script>
316
317 <style lang="scss" scoped>
318 .explains{font-size: 28rpx;color: #999;margin-top: 40rpx;line-height: 2;}
319 :deep(.uni-list-cell::after) {
320 background-color: #eee;
321 width: 94%;
322 left: 3%;
323 }
324
325 .kcitem {
326 margin: 30rpx auto;
327 width: 700rpx;
328 box-sizing: border-box;
329 }
330
331 .whitebg {
332 background: #fff;
333 }
334
335 .rrcard .box {
336 padding: 0 0 1px;
337 margin: 20rpx 0 0;
338 }
339
340 .rrcard {
341 position: relative;
342 padding: 0 25rpx;
343 box-sizing: border-box;
344 }
345
346 .rrcard .t {
347 font-weight: 500;
348 color: #2B3133;
349 margin: 0 0 20rpx;
350 font-size: 32rpx;
351 }
352
353 .fixedBottom {
354 .flexbox {
355 width: 100%;
356 justify-content: space-between;
357 padding: 0 30rpx;
358 }
359 }
360 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <!-- <web-view :src="vUrl"></web-view> -->
4 <view class="whitebg">
5 <image class="ccover" v-if="form.coursePic&&!playVideo&&!playAudio" mode="aspectFill" :src="config.baseUrl_api + form.coursePic"></image>
6 <video v-if="playVideo" @timeupdate="videoing" id="myVideo" :autoplay="false"
7 :src="vUrl" controls @error="videoErrorCallback"
8 play-btn-position="center" controlslist="nodownload"
9 style="width: 100%;"
10 ></video>
11 <audio v-if="playAudio" style="text-align: left" :src="config.baseUrl_api+form.audioUrl?.url"
12 :poster="config.baseUrl_api+form.coursePic" :name="form.audioUrl?.name" :author="form.speaker" controls
13 @timeupdate="audioing" id="myAudio"></audio>
14
15 <view class="name">{{form.courseName}}
16 <view v-if="isBuy" style="font-size: 32rpx;color: #1EC886;display: inline-block;float: right;">
17 <uni-icons color="#1EC886" size="22" type="checkbox-filled"></uni-icons>已兑换
18 </view>
19 </view>
20 <!-- <view class="text-warning pp">{{form.explains}}</view> -->
21 <view class="text-warning pp" v-if="form.isFree==1">
22 <text v-if="form.allGold>0">金币{{form.allGold}}</text>
23 <text v-if="form.allGold>0&&form.allScore>0">/</text>
24 <text v-if="form.allScore>0">积分{{form.allScore}}</text>
25 <text v-if="form.gold>0">/金币{{form.gold}}+积分{{form.score}}</text>
26 </view>
27 <view class="text-warning pp" v-else>免费</view>
28 </view>
29
30 <view class="plane">
31 <view class="phead">
32 <view>
33 <image class="tag01" src="@/course/img/tag01.png" style="width:30rpx;height: 30rpx;"></image>
34 课程介绍
35 </view>
36 <view class="text-warning">讲师:{{form.speaker}}</view>
37 </view>
38 <view class="pbody">
39 {{form.description}}
40 </view>
41 </view>
42
43 <!-- list -->
44 <view class="wList" v-if="form.audioUrl">
45 <view class="pp">
46 <image src="@/course/img/book.png" style="width:24rpx;height: 24rpx;"></image>
47 音频
48 </view>
49 <view class="name">{{form.audioUrl.name}}</view>
50 <view class="playBtn" @click="play('a')">
51 <image src="@/course/img/play.png" style="width:48rpx;height: 48rpx;"></image>
52 </view>
53 </view>
54 <view class="wList" v-if="form.videoUrl">
55 <view class="pp">
56 <image src="@/course/img/book.png" style="width:24rpx;height: 24rpx;"></image>
57 视频
58 </view>
59 <view class="name">{{form.videoUrl.name}}</view>
60 <view class="playBtn" @click="play('v')">
61 <image src="@/course/img/play.png" style="width:48rpx;height: 48rpx;"></image>
62 </view>
63 </view>
64 <!-- <view v-if="!isBuy" style="padding:0 30rpx;">
65 <view class="text-warning">未购买可体验十秒</view>
66 </view> -->
67
68 <view style="height: 200rpx;"></view>
69 <view class="fixedBottom">
70 <!-- form.isFree==1&&!isBuy -->
71 <button class="btn btn-submit" v-if="!isBuy" @click="goBill">立即兑换</button>
72 <button class="btn btn-submit" v-else @click="goBill">立即学习</button>
73 </view>
74 </view>
75 </template>
76
77 <script setup>
78 import {
79 onLoad,
80 onShow,onReady
81 } from '@dcloudio/uni-app';
82 import config from '@/config.js';
83 import {
84 ref,
85 getCurrentInstance
86 } from 'vue';
87 import * as api from '@/common/api.js';
88
89 const form = ref({})
90 const playVideo = ref(false)
91 const playAudio = ref(false)
92 const isBuy = ref(false)
93 const myvideo = ref(null)
94 const myaudio = ref(null)
95 const vUrl = ref('')
96 const system = uni.getStorageSync('systemType')
97 let goodsId = ''
98 onLoad((option) => {
99 if (option.id) {
100 goodsId = option.id
101 }
102 uni.showShareMenu({
103 withShareTicket: true,
104 menus: ['shareAppMessage', 'shareTimeline']
105 });
106 getData(goodsId)
107 })
108 onShow(() => {
109 api.getUserIsPay({
110 orderType: 0,
111 goodsId: goodsId
112 }).then(Response => {
113 isBuy.value = Response.data
114 })
115 })
116 function getData(id) {
117 uni.showLoading({
118 title: '加载中'
119 })
120 api.getCourseById(id).then(res => {
121 form.value = res.data
122 if (form.value.audioUrl) {
123 form.value.audioUrl = JSON.parse(form.value.audioUrl)
124 myaudio.value = uni.createVideoContext('myAudio', this)
125 }
126 if (form.value.videoUrl) {
127 form.value.videoUrl = JSON.parse(form.value.videoUrl)
128 vUrl.value = config.baseUrl_api+form.value.videoUrl?.url
129 myvideo.value = uni.createVideoContext('myVideo', this)
130 myvideo.value.stop()
131 }
132 uni.hideLoading()
133 console.log(vUrl.value)
134 })
135 }
136
137 function goBill() {
138 if(isBuy.value){
139 if(form.value.videoUrl){
140 play('v')
141 } else if(form.value.audioUrl){
142 play('a')
143 }
144 }else{
145 if(form.value.isFree == 0){
146 api.submitOrder({
147 orderType: 0,
148 goodsId: form.value.courseId,
149 payType: "0"
150 }).then(res => {
151 uni.showModal({
152 content:'已兑换!',
153 success:function(respons){
154 if(respons.confirm){
155 api.getUserIsPay({
156 orderType: 0,
157 goodsId: goodsId
158 }).then(Response => {
159 isBuy.value = Response.data
160 })
161 }
162 }
163 })
164 })
165 } else {
166 const obj = encodeURIComponent(JSON.stringify(form.value))
167 let path = `/course/courseBill?form=${obj}`
168 uni.navigateTo({
169 url: path
170 });
171
172 }
173
174 }
175 }
176
177 function play(flag) {
178 // const mate = encodeURIComponent(JSON.stringify(form.value))
179 if(flag=='v'){
180 console.log(vUrl.value)
181 playVideo.value = true
182 playAudio.value = false
183 myvideo.value.play()
184 }
185 if(flag=='a'){
186 playAudio.value = true
187 playVideo.value = false
188 myaudio.value.play()
189 }
190 // if (isBuy.value) {
191 // let path = `/course/play/play?obj=${mate}&flag=${flag}&isBuy=${isBuy.value}`
192 // uni.navigateTo({
193 // url: path
194 // });
195
196 // } else {
197 // uni.showToast({
198 // title: '请购买课程',
199 // icon: 'none'
200 // })
201 // }
202 }
203 function videoErrorCallback(e){
204 console.log(e)
205 }
206 function videoing(e) {
207 // console.log(e.detail.currentTime)
208 if (form.value.isFree==1 && !isBuy.value && e.detail.currentTime > 10) {
209 console.log('111')
210 myvideo.value.pause()
211 playVideo.value = false
212 uni.showModal({
213 content: '试看结束,请兑换课程',
214 success: function(res) {
215 if (res.confirm) {
216 goBill()
217 } else {
218 myvideo.value.stop()
219 }
220 }
221 })
222 }
223 }
224
225 function audioing(e) {
226 // console.log(e.detail.currentTime)
227 if (form.value.isFree==1 && !isBuy.value && e.detail.currentTime >= 10) {
228 console.log('111')
229 myaudio.value.stop()
230 playAudio.value = false
231 uni.showModal({
232 content: '试看结束,请兑换课程',
233 success: function(res) {
234 if (res.confirm) {
235 goBill()
236 }
237 }
238 })
239 }
240 }
241 </script>
242
243 <style scoped lang="scss">
244 .whitebg {
245 background: #fff;
246 padding: 25rpx;
247 }
248
249 .plane {
250 background: #fff;
251 width: 700rpx;
252 border-radius: 15rpx;
253 margin: 30rpx auto;
254 padding: 25rpx;
255 box-sizing: border-box;
256
257 .phead {
258 border-bottom: 1rpx solid #eee;
259 display: flex;
260 justify-content: space-between;
261 padding: 0 0 15rpx;
262 align-items: center;
263 font-size: 30rpx;
264 box-sizing: border-box;
265
266 .text-warning {
267 font-size: 28rpx;
268 }
269
270 .tag01 {}
271 }
272
273 .pbody {
274 padding: 15rpx 0;
275 box-sizing: border-box;
276 line-height: 40rpx;
277 font-size: 28rpx;
278 color: #4C5359;
279 }
280 }
281
282 .wList {
283 background: #fff;
284 padding: 36rpx 23rpx;
285 box-sizing: border-box;
286 border-radius: 15rpx;
287 width: 700rpx;
288 margin: 0 auto 30rpx;
289 position: relative;
290
291 .pp {
292 display: flex;
293 color: #8F8E94;
294 font-size: 24rpx;
295 align-items: center;
296
297 image {
298 margin-right: 6rpx;
299 }
300 }
301
302 .name {
303 color: #2B3133;
304 font-size: 30rpx;
305 margin: 15rpx 0 0;
306 }
307
308 .playBtn {
309 position: absolute;
310 right: 24rpx;
311 top: 0;
312 bottom: 0;
313 margin: auto;
314 height: 48rpx;
315 }
316 }
317
318 .text-warning {
319 color: #F39800;
320 }
321
322 .ccover {
323 width: 700rpx;
324 margin: 0 auto 30rpx;
325 display: block;
326 height: 320rpx;
327 background: #85A6E0;
328 border-radius: 15rpx;
329 }
330
331 .whitebg {
332 .name {
333 font-size: 32rpx;
334 }
335
336 .text-warning {
337 font-size: 26rpx;
338 margin: 10rpx 0 0;
339 }
340 }
341 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view class="playBox" v-show="!loading">
3 <audio v-if="flag=='a'" style="text-align: left" :src="config.baseUrl_api+form.audioUrl?.url"
4 :poster="config.baseUrl_api+form.coursePic" :name="form.audioUrl?.name" :author="form.speaker" controls
5 @timeupdate="audioing" id="myAudio"></audio>
6 <video v-if="flag=='v'" ref="myvideo" @timeupdate="videoing" id="myVideo"
7 :src="config.baseUrl_api+form.videoUrl?.url" controls></video>
8 <view v-if="isBuy=='false'">
9 <view class="text-warning" v-if="flag=='v'">未购买可试看十秒</view>
10 <view class="text-warning" v-if="flag=='a'">未购买可试听十秒</view>
11 </view>
12 </view>
13 </template>
14
15 <script setup>
16 import {
17 onLoad,
18 onShow,
19 onReady
20 } from '@dcloudio/uni-app';
21 import config from '@/config.js';
22 import {
23 ref,
24 getCurrentInstance
25 } from 'vue';
26 import * as api from '@/common/api.js';
27 const form = ref({})
28 const flag = ref('')
29 const isBuy = ref()
30 const myvideo = ref(null)
31 const myaudio = ref(null)
32 const loading = ref(true)
33 onLoad((option) => {
34 console.log(option)
35 if ('obj' in option) {
36 form.value = JSON.parse(decodeURIComponent(option.obj))
37 console.log(form.value.videoUrl.url)
38 loading.value = false
39 }
40 flag.value = option.flag
41 isBuy.value = option.isBuy
42 })
43 onReady(() => {
44 if (flag.value == 'a') {
45 uni.setNavigationBarTitle({
46 title: form.value.audioUrl.name
47 });
48 myaudio.value = uni.createVideoContext('myAudio', this)
49 } else if (flag.value == 'v') {
50 uni.setNavigationBarTitle({
51 title: form.value.videoUrl.name
52 });
53 myvideo.value = uni.createVideoContext('myVideo', this)
54 }
55 })
56
57 function videoing(e) {
58 // console.log(e.detail.currentTime)
59 if (e.detail.currentTime > 10) {
60 myvideo.value.pause()
61 uni.showModal({
62 content: '试看结束,请购买课程',
63 success: function(res) {
64 if (res.confirm) {
65 uni.navigateBack()
66 } else {
67 myvideo.value.stop()
68 }
69 }
70 })
71 }
72 }
73
74 function audioing(e) {
75 // console.log(e.detail.currentTime)
76 if (e.detail.currentTime > 10) {
77 myaudio.value.pause()
78 uni.showModal({
79 content: '试看结束,请购买课程',
80 success: function(res) {
81 if (res.confirm) {
82 uni.navigateBack()
83 } else {
84 myaudio.value.stop()
85 }
86 }
87 })
88 }
89 }
90 </script>
91
92 <style scoped lang="scss">
93 .playBox {
94 text-align: center;
95 margin: 5vh 0;
96 }
97 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view style="height: calc(100vh - 150rpx);overflow: auto;">
4 <view class="coverbox">
5 <!-- <image class="cover" :src="config.baseUrl_api+form.images"/> -->
6 <image class="cover" src="@/exam/img/bg@2x.png"/>
7 <view class="name">{{form.paperName}}</view>
8 </view>
9 <view class="card">
10 <view class="beif">{{form.instruction}}</view>
11
12 <view class="garybox">
13 <view>关键字:{{form.tags}}</view>
14 <view>适用范围:{{form.radius}}</view>
15 <view>题目数量:10</view>
16 <view>评定时间:{{form.evalTime}}分钟</view>
17 </view>
18
19 <view class="redbox">
20 <view class="tt">指导语</view>
21 <view>{{form.description}}</view>
22 </view>
23
24 </view>
25 </view>
26 <view class="bottomFunc">
27 <button class="submit-btn" v-if="status==-1" style="width: 380rpx;" @click="start(0)">开始测评</button>
28 <button class="submit-btn" v-if="status==0" style="width: 380rpx;" @click="start(1)">继续测评</button>
29 <button class="submit-btn" v-if="status==1" @click="start(2)">重新测评</button>
30 <button class="submit-btn2" v-if="status==1" @click="goResult">查看结果</button>
31 </view>
32
33
34 <uni-popup ref="popYanZheng" type="center">
35 <view class="popup-body">
36 <view class="tt">请输入个人信息</view>
37 <uni-forms>
38 <uni-forms-item label="姓名">
39 <uni-easyinput v-model="formPut.nickName" placeholder="请输入姓名" />
40 </uni-forms-item>
41 <uni-forms-item label="手机号码">
42 <uni-easyinput v-model="formPut.phonenumber" placeholder="请输入手机号码" />
43 </uni-forms-item>
44
45
46 <button class="submit-btn" style="width: 380rpx;" @click="submitForm">开始测评</button>
47 </uni-forms>
48 </view>
49 </uni-popup>
50 </view>
51
52 </template>
53
54 <script setup>
55 import {
56 onLoad,onShow
57 } from '@dcloudio/uni-app'
58 import * as api from '@/common/api.js';
59 import config from '@/config.js';
60 import * as loginServer from '@/common/login.js';
61 import _ from 'lodash'
62 import {
63 ref,
64 getCurrentInstance
65 } from 'vue';
66 import dayjs from 'dayjs'
67 const app = getApp();
68
69 const {
70 proxy
71 } = getCurrentInstance()
72
73 const current = ref(0);
74 const popYanZheng = ref(null);
75 const form = ref({});
76 const status = ref(0);
77 const formPut = ref({});
78 let paperId = ''
79 onShow(() => {
80 if (app.globalData.isLogin) {
81 init();
82 } else {
83 app.firstLoadCallback = () => {
84 init();
85 };
86 }
87 })
88 onLoad((option) => {
89 uni.showLoading({
90 title: '加载中'
91 });
92 paperId = option.id
93 })
94 function init(){
95 api.getPaperInfo(paperId).then(res=>{
96 form.value = res.data
97 uni.hideLoading()
98 })
99 api.getState(paperId).then(res=>{
100 status.value = res.msg
101 })
102 }
103 let currUser
104 function checkUserPhone() {
105 currUser = uni.getStorageSync('currUser')
106 if (!currUser) {
107 loginServer.pcLogin().then(() => {
108 currUser = uni.getStorageSync('currUser')
109 if (currUser.phonenumber) {
110 return true
111 } else {
112 popYanZheng.value.open()
113 return false;
114 }
115 });
116 } else {
117 if (currUser.phonenumber) {
118 return true
119 } else {
120 popYanZheng.value.open()
121 return false;
122 }
123 }
124 }
125 function start(flag){
126 //验证手机号
127 if (checkUserPhone()) {
128 goDoText(flag)
129 }
130 }
131 function goDoText(flag){
132 let path = `/exam/subject?id=${paperId}&flag=${flag}`;
133 uni.navigateTo({
134 url: path
135 });
136
137 }
138 function goResult(){
139 let path = `/exam/result?id=${paperId}`;
140 uni.navigateTo({
141 url: path
142 });
143 }
144 // 订阅
145 function subscribe() {
146 // 场馆预订成功通知 订场取消提醒 订单退款通知
147 uni.requestSubscribeMessage({
148 tmplIds: ['p7_a1SGyGvJeOdwx_GKl6UlrWiWpNnejUArbnEPf-k4'],
149 success: (res) => {
150 console.log('success:', res)
151 }
152 })
153 }
154 function submitForm(flag){
155 if(!formPut.value.nickName){
156 uni.showToast({
157 title:`请输入姓名`,
158 icon:'none'
159 })
160 return
161 }
162 if(!formPut.value.phonenumber){
163 uni.showToast({
164 title:`请输入手机号码`,
165 icon:'none'
166 })
167 return
168 }
169 api.updateUserInfo(formPut.value).then(res=>{
170 goDoText()
171 loginServer.getCurrUser()
172 })
173 }
174 </script>
175
176 <style lang="scss" scoped>
177 .card{background: #fff;border-radius: 30rpx;padding: 50rpx 40rpx;
178 position: relative;top:-30rpx;
179 .beif{font-size: 30rpx;}
180 }
181 .garybox{border-radius: 15rpx;background: #F5F8FA;padding: 30rpx 38rpx;margin-top: 30rpx;
182 font-size: 30rpx;line-height: 2;color: #030303;
183 }
184 .redbox{border-radius: 15rpx;background: rgba(242, 156, 159, 0.36);padding: 30rpx 38rpx;
185 margin-top: 30rpx;line-height: 1.5;
186 .tt{color: RGBA(230, 0, 18, 1);margin-bottom:26rpx;
187 font-weight: 600;}
188 }
189 .popup-body{ background-color: #fff;padding: 50rpx;
190 .tt{margin-bottom:40rpx;}
191 }
192 .coverbox{height: 240rpx;position: relative;
193 .cover{width: 100%;height: 240rpx;}
194 .name{position: absolute;color: #fff;
195 font-size: 36rpx;top:40%;left: 40rpx;width: 8em;}
196 }
197 </style>
1 <template>
2 <view>
3 <view class="whitebg">
4 <view class="resultbox" v-for="(form,index) in formlist" :key="index">
5 <view class="ppbar">
6 <view class="bar-text">
7 <view v-for="n in form.evalTutorVoList" :style="{width: ((n.maxScore-n.minScore)/(form.evalTutorVoList[form.evalTutorVoList.length-1]?.maxScore-form.evalTutorVoList[0]?.minScore)*100) +'%'}">
8 <text class="brr">123</text>
9 <!-- <view>
10 <text>{{Math.floor(n.minScore)}}</text>
11 <text>{{Math.floor(n.maxScore)}}</text>
12 </view> -->
13 </view>
14 </view>
15 <view class="bar-bg"></view>
16 <view class="dotbox" :style="{left: (form.score/(form.evalTutorVoList[form.evalTutorVoList.length-1]?.maxScore-form.evalTutorVoList[0]?.minScore)*100) +'%'}">
17 <text>{{form.score}}</text>
18 <image src="@/exam/img/dian.png" />
19 </view>
20 </view>
21 <view>
22 <view class="flexline" v-if="formlist.length>1">
23 <label>测评条目</label>
24 <view>{{form.title}}</view>
25 </view>
26 <view class="flexline">
27 <label>测评结果</label>
28 <view>{{form.desc}}</view>
29 </view>
30 <view class="flexline">
31 <label>辅导建议</label>
32 <view>{{form.expression}}</view>
33 </view>
34 </view>
35 </view>
36
37 <view class="content">
38 {{paperInfo.instruction}}
39 </view>
40 <button class="sharebtn" @click="showRecmand">分享测试</button>
41 <!-- <button class="sharebtn" open-type="share" @click="showRecmand">分享测试</button> -->
42 </view>
43
44 <view v-if="reclist?.length>0">
45 <view class="tbar">
46 相关测评
47 </view>
48 <view class="list">
49 <view class="item" v-for="n in reclist" :key="n" @click="goDetail">
50 <image :src="config.baseUrl_api + n.images"></image>
51 <view class="info">
52 <view class="tt esp_2">{{n.paperName}}</view>
53 </view>
54 </view>
55 </view>
56 </view>
57 </view>
58 </template>
59
60 <script setup>
61 import * as api from '@/common/api.js';
62 import config from '@/config.js';
63 import {
64 onLoad,
65 onShow,
66 onShareAppMessage,
67 onShareTimeline,
68 onPullDownRefresh
69 } from '@dcloudio/uni-app';
70 import {
71 ref,
72 getCurrentInstance
73 } from 'vue';
74 const app = getApp();
75 const formlist = ref([])
76 const paperInfo = ref({})
77 const reclist = ref([])
78 const recImg = ref('')
79 let paperId = ''
80 onLoad((option)=>{
81 paperId = option.id
82 })
83 onShow(() => {
84 if (app.globalData.isLogin) {
85 init();
86 } else {
87 app.firstLoadCallback = () => {
88 init();
89 };
90 }
91 })
92 function init(){
93 uni.showLoading({
94 title:'加载中'
95 })
96 api.getUserAnswerResult({paperId:paperId}).then(res=>{
97 formlist.value = res.data
98 uni.hideLoading()
99 })
100 api.getPaperInfo(paperId).then(res=>{
101 paperInfo.value = res.data
102 })
103 getReclist()
104 }
105 function getReclist(){
106 api.getHomePageHot().then(res=>{
107 reclist.value = res.data
108 })
109 }
110 onShareAppMessage(() => {
111 return {
112 title: '',
113 path: `/exam/subject?id=${paperId}`
114 // imageUrl: app.globalData.baseUrl + project.value.proPic
115 };
116 });
117 onShareTimeline(() => {
118 return {
119 title: '',
120 path: '/pages/index/index'
121 // imageUrl: app.globalData.baseUrl + project.value.proPic
122 };
123 });
124 function showRecmand(){
125 uni.showLoading({
126 title:'加载中'
127 })
128 const currUser = uni.getStorageSync('currUser')
129 api.getExclusiveImage(currUser.userId).then(res=>{
130 recImg.value = 'data:image/png;base64,' + res.msg
131 // showRecImg.value = true
132 clickImg()
133 uni.hideLoading()
134 })
135 }
136 function clickImg() {
137 uni.previewImage({
138 urls: [recImg.value],
139 // current: 0,
140 success: function(res) {
141 console.log('success', res)
142 },
143 fail: function(res) {
144 console.log('fail', res)
145 },
146 complete: function(res) {
147 console.log('complete', res)
148 }
149 })
150 }
151 </script>
152
153 <style lang="scss" scoped>
154 .whitebg {
155 background: #fff;
156 padding: 60rpx 30rpx;
157 }
158
159 .resultbox {
160 color: #fff;margin: 0 0 20rpx;
161 padding: 30rpx;border-radius: 20rpx;overflow: hidden;
162 background: linear-gradient(90deg, #81A7F3, #A2CCF1);
163
164 .ppbar {
165 position: relative;margin-bottom: 40rpx;
166
167 .bar-bg {
168 height: 10rpx;
169 background: #fff;
170 opacity: 0.4;
171 border-radius: 0rpx;position: absolute;width: 100%;
172 left: 0;top: 100rpx;
173 }
174
175 .bar-text {background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,0.6));
176 text-align: center;
177 display: flex;
178 justify-content: space-between;
179 font-size: 28rpx;
180
181 // line-height: 100rpx;
182 .brr{border-right: 1rpx solid #82a7f3;height: 100rpx;display: inline-block;
183 width: 100%;text-align: center;color: transparent;}
184 view {flex: 1 1 auto;
185 view{display: flex;justify-content: space-between;
186 text{padding: 0 4rpx;opacity: 0;}
187 }
188 &:last-child .brr{border-right:none;}
189 }
190
191 }
192
193 .dotbox {text-align: center;margin-left: -32rpx;
194 position: absolute;top: 26rpx;
195 text{display: block;font-size: 34rpx;font-weight: bold;padding: 0 10rpx;
196 color: #82a7f3; margin: 0 0 14rpx 0;background-color: #fff;border-radius: 10rpx;
197 position: relative;
198 &::after{
199 content: '';position: absolute;bottom: -10rpx;left: 0;right: 0;
200 margin: auto;
201 width: 0;
202 height: 0;
203 border-left: 10rpx solid transparent;
204 border-right: 10rpx solid transparent;
205 border-top: 10rpx solid #fff;
206 }
207 }
208 image {
209 width: 42rpx;
210 height: 42rpx;
211 }
212 }
213 }
214
215 .flexline {
216 display: flex;margin: 0 0 20rpx;
217
218 label {
219 opacity: 0.6; flex: 0 0 auto;
220 margin-right: 40rpx;
221 }
222 view{
223 flex: 1 1 auto;
224 }
225 }
226 }
227
228 .content {padding: 20rpx;
229 margin: 20rpx 0;
230 font-size: 30rpx;
231 font-weight: 400;
232 line-height: 44rpx;
233 color: #030303;
234 }
235
236 .sharebtn {
237 height: 70rpx;
238 width: 50%;
239 color: #FFFFFF;
240 font-size: 30rpx;
241 background: #F89D46;
242 border-radius: 35rpx;
243 }
244
245 .list {
246 padding: 24rpx 0 0 24rpx;
247 overflow: hidden;
248 }
249
250 .item {
251 border-radius: 15rpx;
252 background: #fff;
253 width: 338rpx;
254 float: left;
255 margin: 0 24rpx 24rpx 0;
256
257 image {
258 height: 180rpx;
259 width: 100%;
260 }
261
262 .info {
263 padding: 20rpx 26rpx;
264 height: 100rpx;
265 box-sizing: border-box;
266
267 .tt {
268 font-size: 28rpx;
269 line-height: 36rpx;
270 }
271 }
272 }
273
274 .tbar {
275 padding: 0 25rpx;
276 margin: 40rpx 0 10rpx;
277
278 text {
279 float: right;
280 color: #929AA0;
281 background: #fff;
282 border-radius: 20rpx;
283 padding: 0 14rpx;
284 }
285 }
286 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view>
4 <!-- 进度条 -->
5 <view class="progress">
6 <view><text class="bigsize">{{current}}</text>/{{list.length}}</view>
7 <view class="pbody">
8 <view class="pxin" :style="{width: current/list.length*100 +'%'}"></view>
9 </view>
10 </view>
11 <view class="sArea" v-for="(s,index) in list" :key="index" v-show="current == Number(s.quesNo)">
12 <view class="tgan">
13 <text class="must">*</text>
14 {{s.quesNo}}. {{s.quesTitle}}
15 </view>
16
17 <view class="option" v-for="(o, oindex) in s.evalOptionsList" :key="oindex" :class="o.status==1?'active':''"
18 @click="changeOption(o,s.evalOptionsList)">
19 <view class="check">
20 <image src="@/exam/img/xz@2x.png" />
21 </view>
22 <view class="checked">
23 <image src="@/exam/img/xz_dwn@2x.png" />
24 </view>
25 {{opArr[oindex]}}. {{o.title}}
26 </view>
27 </view>
28
29 <view class="bottomFunc">
30 <view v-if="current==1" style="opacity: 0.5"><image src="@/exam/img/prev@2x.png"/>上一题</view>
31 <view v-else @click="goPrev"><image src="@/exam/img/prev@2x.png"/>上一题</view>
32 <view @click="submit" class="submit-btn" v-if="current == list.length">提交测评</view>
33 <view v-if="canNext&&current != list.length" @click="goNext">下一题<image src="@/exam/img/next@2x.png"/></view>
34 <view v-if="!canNext&&current != list.length" style="opacity: 0.5" @click="showTip">下一题<image src="@/exam/img/next@2x.png"/></view>
35 </view>
36 </view>
37
38 </view>
39 </template>
40
41 <script setup>
42 import {
43 nextTick,
44 ref
45 } from 'vue';
46 import {
47 onLoad,
48 onShow
49 } from '@dcloudio/uni-app';
50 import _ from 'lodash';
51 import dayjs from 'dayjs';
52 import * as api from '@/common/api.js';
53
54 const app = getApp();
55 const list = ref([])
56 const options = ref([])
57 const query = ref({
58 state:0
59 })
60 const current = ref(1)
61 const canNext = ref(false)
62 const opArr = ref(['A','B','C','D','E','F'])
63 let answerId = ''
64 let flag = 0
65 onLoad(option=>{
66 query.value.paperId = option.id
67 if(option.flag){
68 flag = option.flag
69 }
70 console.log(option.flag)
71 })
72 onShow(() => {
73 if (app.globalData.isLogin) {
74 init()
75 } else {
76 app.firstLoadCallback = () => {
77 init()
78 };
79 }
80 });
81 function init(){
82 uni.showLoading({
83 title:'加载中'
84 })
85 if(flag==2){
86 // 重新测评
87 query.value.state = 1
88 }
89 api.getUserAnswerInfo(query.value).then(res=>{
90 list.value = res.data.userAnswerList
91 answerId = res.data.answerId
92 if(flag==1){
93 skip()
94 }
95 uni.hideLoading()
96 })
97 }
98 function skip(){
99 for(var item of list.value){
100 for(var option of item.evalOptionsList){
101 if(option.status == 1){
102 current.value = current.value + 1
103 }
104 }
105 }
106 console.log(current.value)
107 }
108 function changeOption(t,list){
109 // 单选
110 for(var item of list){
111 if(item.optionId == t.optionId){
112 if(item.status == 1){
113 item.status = 0
114 canNext.value = false
115 }else{
116 item.status = 1
117 canNext.value = true
118 }
119 } else {
120 item.status = 0
121 }
122 }
123 }
124 function showTip(){
125 uni.showToast({
126 title:'请选择后前往下一题',
127 icon:'none'
128 })
129 }
130 function goNext(){
131 current.value = current.value + 1
132 canNext.value = false
133 for(var item of list.value){
134 if(item.quesNo==current.value){
135 for(var option of item.evalOptionsList){
136 if(option.status == 1){
137 canNext.value = true
138 }
139 }
140 }
141
142 }
143 save()
144 }
145 function goPrev(){
146 current.value = current.value - 1
147 canNext.value = true
148 }
149 function save(){
150 var obj = {
151 answerId:answerId,
152 paperId:query.value.paperId,
153 userAnswerList:list.value
154 }
155 api.saveAnswer(obj).then(res=>{
156
157 })
158 }
159 function submit(){
160 if(canNext.value){
161 uni.showLoading({
162 title:'提交中'
163 })
164 var obj = {
165 answerId:answerId,
166 paperId:query.value.paperId,
167 userAnswerList:list.value
168 }
169 api.submitAnswer(obj).then(res=>{
170 uni.hideLoading()
171 let path = `/exam/result?id=${query.value.paperId}`
172 uni.redirectTo({
173 url: path
174 });
175 })
176 } else {
177 uni.showToast({
178 title:'请选择后提交',
179 icon:'none'
180 })
181 }
182
183 }
184 </script>
185 <style lang="scss" scoped>
186 .progress {
187 color: #8F8E94;
188 font-size: 30rpx;
189 padding: 20rpx;
190 display: flex;
191 align-items: center;
192
193 .bigsize {
194 color: #030303;
195 font-size: 48rpx;
196 }
197
198 .pbody {
199 height: 10rpx;
200 background: #D0D5D8;
201 border-radius: 5rpx;
202 width: 100%;
203 margin-left: 20px;
204 position: relative;
205 overflow: hidden;
206
207 .pxin {
208 background: linear-gradient(90deg, #FFCE56, #F79A45);
209 height: 100%;
210 border-radius: 5rpx;
211 }
212 }
213 }
214
215 .must {
216 color: #DC0032;
217 }
218
219 .sArea {
220 background: #fff;
221 padding: 25rpx;
222 border-radius: 30rpx;
223
224 .tgan {
225 padding: 20rpx;
226 line-height: 1.6;
227 text-align: justify;
228 }
229
230 .option {
231 padding: 30rpx;
232 color: #000000;
233 font-size: 30rpx;
234 background: #F5F8FA;
235 margin-bottom: 20rpx;
236 border-radius: 20rpx;
237 display: flex;
238
239 &.active {
240 color: #fff;
241 // background: #F89D46;
242 background: linear-gradient(90deg, #fec45a, #F89D46);
243 .check {
244 display: none;
245 }
246
247 .checked {
248 display: block;
249 }
250 }
251
252 .check {
253 display: block;
254 margin-right: 20rpx;
255 }
256
257 .checked {
258 display: none;
259 margin-right: 20rpx;
260 }
261
262 .check image {
263 width: 40rpx;
264 height: 40rpx;
265 }
266
267 .checked image {
268 width: 40rpx;
269 height: 40rpx;
270 }
271 }
272 }
273 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <script>
6 var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
7 CSS.supports('top: constant(a)'))
8 document.write(
9 '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
10 (coverSupport ? ', viewport-fit=cover' : '') + '" />')
11 </script>
12 <title>心理测评</title>
13 <!--preload-links-->
14 <!--app-context-->
15 <style>
16 * {
17 box-sizing: border-box;
18 }
19 </style>
20 </head>
21 <body>
22 <div id="app"><!--app-html--></div>
23 <script type="module" src="/main.js"></script>
24 </body>
25 </html>
1 import App from './App'
2 // #ifndef VUE3
3 import Vue from 'vue'
4 Vue.config.productionTip = false
5 App.mpType = 'app'
6 const app = new Vue({
7 ...App
8 })
9 app.$mount()
10 // #endif
11
12 // #ifdef VUE3
13 import {
14 createSSRApp
15 } from 'vue'
16 export function createApp() {
17 const app = createSSRApp(App)
18 return {
19 app
20 }
21 }
22 // #endif
1 {
2 "name" : "baize",
3 "appid" : "__UNI__580BCB0",
4 "description" : "",
5 "versionName" : "1.0.1",
6 "versionCode" : "100",
7 "transformPx" : false,
8 /* 5+App特有相关 */
9 "app-plus" : {
10 "usingComponents" : true,
11 "nvueStyleCompiler" : "uni-app",
12 "compilerVersion" : 3,
13 "splashscreen" : {
14 "alwaysShowBeforeRender" : true,
15 "waiting" : true,
16 "autoclose" : true,
17 "delay" : 0
18 },
19 /* 模块配置 */
20 "modules" : {},
21 /* 应用发布信息 */
22 "distribute" : {
23 /* android打包配置 */
24 "android" : {
25 "permissions" : [],
26 "autoSdkPermissions" : true
27 },
28 /* ios打包配置 */
29 "ios" : {
30 "permissions" : [],
31 "autoSdkPermissions" : true
32 },
33 /* SDK配置 */
34 "sdkConfigs" : {}
35 }
36 },
37 /* 快应用特有相关 */
38 "quickapp" : {},
39 /* 小程序特有相关 */
40 "mp-weixin" : {
41 "appid" : "wxc1e303a29052b843", //
42 "setting" : {
43 "urlCheck" : false,
44 "minified" : false,
45 "es6" : true
46 },
47 "usingComponents" : true,
48 "permission" : {},
49 "optimization" : {
50 "subPackages" : true
51 }
52 },
53 "mp-alipay" : {
54 "usingComponents" : true
55 },
56 "mp-baidu" : {
57 "usingComponents" : true
58 },
59 "mp-toutiao" : {
60 "usingComponents" : true
61 },
62 "uniStatistics" : {
63 "enable" : false
64 },
65 "vueVersion" : "3"
66 }
1 {
2 "dependencies": {
3 "dayjs": "^1.11.6",
4 "lodash": "^4.17.21"
5 },
6 "devDependencies": {
7 "@rollup/plugin-commonjs": "^22.0.0"
8 }
9 }
1 {
2 "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
3 {
4 "path": "pages/index/index",
5 "style": {
6 "navigationBarTitleText": "首页",
7 "backgroundColor": "#ffffff",
8 "navigationStyle": "default",
9 "navigationBarTextStyle": "black",
10 "navigationBarBackgroundColor": "#ffffff"
11 }
12 },
13 {
14 "path": "pages/form/index",
15 "style": {
16 "navigationStyle": "default",
17 "navigationBarBackgroundColor": "#F7F8FA",
18 "navigationBarTextStyle": "black",
19 "navigationBarTitleText": "反馈",
20 "enablePullDownRefresh": false
21 }
22
23 }, {
24 "path": "pages/index/list",
25 "style": {
26 "navigationStyle": "default",
27 "navigationBarBackgroundColor": "#F7F8FA",
28 "navigationBarTextStyle": "black",
29 "navigationBarTitleText": "列表",
30 "enablePullDownRefresh": false
31 }
32
33 },
34 {
35 "path": "pages/course/course",
36 "style": {
37 "navigationBarTitleText": "课程",
38 "enablePullDownRefresh": false
39 }
40 },
41 {
42 "path": "pages/active/active",
43 "style": {
44 "navigationBarTitleText": "活动",
45 "enablePullDownRefresh": false
46 }
47 },
48 {
49 "path": "pages/usercenter",
50 "style": {
51 "navigationBarTitleText": "个人中心",
52 "enablePullDownRefresh": false
53 }
54 }
55 ],
56 "globalStyle": {
57 "navigationStyle": "default",
58 "navigationBarBackgroundColor": "#F7F8FA",
59 "navigationBarTextStyle": "black",
60 "navigationBarTitleText": "测评"
61 },
62 "subPackages": [{
63 "root": "usercenter",
64 "pages": [ {
65 "path": "myInfo",
66 "style": {
67 "navigationStyle": "default",
68 "navigationBarBackgroundColor": "#F7F8FA",
69 "navigationBarTextStyle": "black",
70 "navigationBarTitleText": "个人信息",
71 "enablePullDownRefresh": false,
72 "onReachBottomDistance": 100,
73 "backgroundColor": "#ffffff"
74 }
75
76 },
77 {
78 "path": "myPaper",
79 "style": {
80 "navigationBarTitleText": "我的报告",
81 "enablePullDownRefresh": false
82 }
83 },
84 {
85 "path": "myCompany",
86 "style": {
87 "navigationBarTitleText": "机构认证",
88 "enablePullDownRefresh": false
89 }
90 },
91 {
92 "path": "about",
93 "style": {
94 "navigationBarTitleText": "关于我们",
95 "enablePullDownRefresh": false
96 }
97 },
98 {
99 "path": "myReservation",
100 "style": {
101 "navigationBarTitleText": "我的预约",
102 "enablePullDownRefresh": false
103 }
104 },
105 {
106 "path": "myCourse",
107 "style": {
108 "navigationBarTitleText": "我的课程",
109 "enablePullDownRefresh": false
110 }
111 },
112 {
113 "path": "mycard/renew",
114 "style": {
115 "navigationBarTitleText": "金币充值",
116 "enablePullDownRefresh": false
117 }
118 },
119 {
120 "path": "mycard/mycard",
121 "style": {
122 "navigationBarTitleText": "消费记录",
123 "enablePullDownRefresh": false
124 }
125 }
126 ]
127 }, {
128 "root": "course",
129 "pages": [{
130 "path": "courseDetail",
131 "style": {
132 "navigationBarTitleText": "课程详情",
133 "enablePullDownRefresh": false
134 }
135 }, {
136 "path": "activeDetail",
137 "style": {
138 "navigationBarTitleText": "活动详情",
139 "enablePullDownRefresh": false
140 }
141 }, {
142 "path": "courseBill",
143 "style": {
144 "navigationBarTitleText": "课程订单",
145 "enablePullDownRefresh": false
146 }
147
148 }, {
149 "path": "play/play",
150 "style": {
151 "navigationBarTitleText": "播放",
152 "enablePullDownRefresh": false
153 }
154 }]
155 },{
156 "root": "exam",
157 "pages": [{
158 "path": "booking",
159 "style": {
160 "navigationBarTitleText": "详情",
161 "enablePullDownRefresh": false,
162 "navigationStyle": "default",
163 "navigationBarTextStyle": "black",
164 "navigationBarBackgroundColor": "#F7F8FA"
165 }
166 },{
167 "path": "result",
168 "style": {
169 "navigationBarTitleText": "测评结果",
170 "enablePullDownRefresh": false
171 }
172
173 }, {
174 "path": "subject",
175 "style": {
176 "navigationBarTitleText": "测试",
177 "enablePullDownRefresh": false,
178 "navigationStyle": "default",
179 "navigationBarTextStyle": "black",
180 "navigationBarBackgroundColor": "#fff"
181 }
182 }]
183 }],
184 "preloadRule": {
185 "pages/index/index": {
186 "network": "all",
187 "packages": ["usercenter", "course","exam"]
188 }
189 },
190 "tabBar": {
191 "color": "#929AA0",
192 "selectedColor": "#EA8320",
193 "borderStyle": "white",
194 "backgroundColor": "#ffffff",
195 "list": [{
196 "pagePath": "pages/index/index",
197 "text": "首页",
198 "iconPath": "static/home.png",
199 "selectedIconPath": "static/home_dwn.png"
200 },
201 {
202 "pagePath": "pages/index/list",
203 "text": "测评",
204 "iconPath": "static/cp.png",
205 "selectedIconPath": "static/cp_dwn.png"
206
207 },
208 {
209 "pagePath": "pages/course/course",
210 "text": "课程",
211 "iconPath": "static/kc.png",
212 "selectedIconPath": "static/kc_dwn.png"
213 },
214 {
215 "pagePath": "pages/active/active",
216 "text": "活动",
217 "iconPath": "static/hd.png",
218 "selectedIconPath": "static/hd_dwn.png"
219
220 },
221 {
222 "pagePath": "pages/usercenter",
223 "text": "我的",
224 "iconPath": "static/mine.png",
225 "selectedIconPath": "static/mine_dwn.png"
226
227 }
228 ]
229 }
230 }
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view class="search-area">
4 <uni-easyinput prefixIcon="search" v-model="query.activityName" placeholder="搜索活动名称"
5 @clear="getList" @change="getList">
6 </uni-easyinput>
7 </view>
8 <view class="imageFlowBox">
9 <view class="imageFlow">
10 <view v-for="(b,index) in alist" :key="b.activityId" @click="goDetail(b)">
11 <image mode="aspectFit" :src="config.baseUrl_api+b.activityPic" class="cover"></image>
12 </view>
13 </view>
14 </view>
15 <view class="tbar">
16 全部活动
17 </view>
18 <view class="list">
19 <view class="acitem" v-for="n in list" :key="n.activityId" @click="goDetail(n)">
20 <view class="acbody">
21 <image :src="config.baseUrl_api+n.activityPic" mode="aspectFit"></image>
22 <view class="info">
23 <view class="tt">{{n.activityName}}</view>
24 <view class="pp">
25 <uni-icons type="notification" size="12" />
26 {{n.startTime}} ~ {{n.endTime}}
27 </view>
28 <view class="pp mt20">
29 <uni-icons type="location" size="12" />
30 {{n.address}}
31 </view>
32 <view class="text-warning" v-if="n.isFree==1">金币{{n.allGold}}/积分{{n.allScore}}</view>
33 <view class="text-warning" v-else>免费</view>
34 </view>
35 </view>
36 <view class="acfoot">
37 <view>
38 <!-- <uni-icons type="person" size="12"></uni-icons> -->
39 <!-- 已有 222人报名参加 -->
40 </view>
41 <button class="btn btn1">我要报名</button>
42 </view>
43 </view>
44 </view>
45 <view class="nodata" v-if="list.length==0">
46 <image mode="aspectFit" src="/static/nodata.png"></image>
47 </view>
48 </view>
49 </template>
50
51 <script setup>
52 import {
53 onLoad,
54 onShow
55 } from '@dcloudio/uni-app';
56 import config from '@/config.js';
57 import {
58 ref,
59 getCurrentInstance
60 } from 'vue';
61 import * as api from '@/common/api.js';
62 const list = ref([])
63 const alist = ref([])
64 const query = ref({
65 activityName: ''
66 })
67 const system = uni.getStorageSync('systemType');
68 onShow(() => {
69 init()
70 })
71
72 function init() {
73 uni.showLoading({
74 title: `加载中`
75 })
76 getList()
77 getHotList()
78 }
79 function getHotList(){
80 api.getHomePageHotActive().then(res => {
81 alist.value = res.data
82 uni.hideLoading()
83 })
84 }
85 function getList() {
86 api.getActivityList(query.value).then(res => {
87 list.value = res.rows
88 uni.hideLoading()
89 })
90 }
91
92 function goDetail(item) {
93 let path = `/course/activeDetail?id=${item.activityId}`;
94 uni.navigateTo({
95 url: path
96 });
97
98 }
99 </script>
100 <style lang="scss" scoped>
101 .imageFlowBox {
102 position: relative;
103 height: 300rpx;
104 overflow: auto;
105 }
106
107 .imageFlow {
108 display: flex;
109 position: absolute;
110 left: 0;
111 padding: 0 10rpx;
112
113 &>view {
114 border-radius: 10px;
115 overflow: hidden;
116 width: 630rpx;
117 height: 300rpx;
118 margin: 0 10rpx;
119 position: relative;
120 }
121
122 image {
123 width: 630rpx;
124 height: 300rpx;
125 }
126
127 .info {
128 position: absolute;
129 color: #fff;
130 top: 0;
131 width: 100%;
132 height: 100%;
133 padding: 30rpx 40rpx;
134 overflow: hidden;
135 box-sizing: border-box;
136
137 .name {
138 font-size: 34rpx;
139 color: #fff;
140 padding-bottom: 20rpx;
141 margin-bottom: 20rpx;
142 border-bottom: 1px solid RGBA(255, 255, 255, 0.7);
143 }
144 }
145
146 .esp_2 {
147 font-size: 28rpx;
148 margin-bottom: 26rpx;
149 }
150
151 .timeblock {
152 background: rgba(27, 27, 27, 0.1);
153 border-radius: 25rpx;
154 font-size: 22rpx;
155 padding: 12rpx 17rpx;
156 display: inline-flex;
157 align-items: center;
158
159 image {
160 width: 28rpx;
161 height: 28rpx;
162 margin-left: 22rpx;
163 }
164 }
165
166 }
167
168 .list {
169 padding: 24rpx 0 0 24rpx;
170 overflow: hidden;
171 }
172 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view>
3 <view class="search-area">
4 <uni-easyinput prefixIcon="search" v-model="query.courseName" placeholder="搜索课程名称"
5 @change="getList" @clear="getList">
6 </uni-easyinput>
7 </view>
8 <view class="imageFlowBox">
9 <view class="imageFlow">
10 <view v-for="(b,index) in clist" :key="b.courseId" @click="goDetail(b)">
11 <image mode="aspectFill" :src="config.baseUrl_api+b.coursePic" class="cover"></image>
12 <!-- <div class="info">
13 <h3 class="name esp">{{b.paperName}}</h3>
14 <p class="esp_2">{{b.description}}</p>
15 <view class="timeblock">预计用时 {{b.evalTime}}分钟
16
17 </view>
18 </div> -->
19 </view>
20 </view>
21 </view>
22 <view class="tbar">
23 全部课程
24 </view>
25 <view class="list">
26 <view class="kcitem" v-for="n in list" :key="n.courseId" @click="goDetail(n)">
27 <image :src="config.baseUrl_api+n.coursePic" mode="aspectFill"></image>
28 <view class="info">
29 <view class="tt esp_2">{{n.courseName}}</view>
30 <!-- <view class="pp"><uni-icons type="chatboxes" size="12" />209w 学习</view> -->
31 <view class="text-warning" v-if="n.isFree==0">免费</view>
32 <view class="text-warning" v-else>金币{{n.allGold}}/积分{{n.allScore}}</view>
33 </view>
34 </view>
35 </view>
36 <view class="nodata" v-if="list.length==0">
37 <image mode="aspectFit" src="/static/nodata.png"></image>
38 </view>
39 </view>
40 </template>
41
42 <script setup>
43 import {
44 onLoad,
45 onShow
46 } from '@dcloudio/uni-app';
47 import config from '@/config.js';
48 import {
49 ref,
50 getCurrentInstance
51 } from 'vue';
52 import * as api from '@/common/api.js';
53 const list = ref([])
54 const clist = ref([])
55 const kindList = ref([])
56 const kindId = ref('')
57 const query = ref({
58 courseName:''
59 })
60 const system = uni.getStorageSync('systemType');
61 onShow(() => {
62 init()
63 })
64
65 function init() {
66 getList()
67 getHot()
68 }
69 function getHot(){
70 uni.showLoading({
71 title:`加载中`
72 })
73 api.getHomePageHotCourse().then(res => {
74 clist.value = res.data
75 uni.hideLoading()
76 })
77 }
78 function getList() {
79 uni.showLoading({
80 title:`加载中`
81 })
82 api.getCourseList(query.value).then(res => {
83 list.value = res.rows
84 uni.hideLoading()
85 })
86 }
87
88 function goDetail(item) {
89 let path = `/course/courseDetail?id=${item.courseId}`;
90 uni.navigateTo({
91 url: path
92 });
93
94 }
95 </script>
96
97 <style lang="scss" scoped>
98 .imageFlowBox {
99 position: relative;
100 height: 300rpx;
101 overflow: auto;
102 }
103
104 .imageFlow {
105 display: flex;
106 position: absolute;
107 left: 0;
108 padding: 0 10rpx;
109
110 &>view { border-radius: 10px;
111 overflow: hidden;
112 width: 630rpx;
113 height: 300rpx;
114 margin: 0 10rpx;
115 position: relative;
116 }
117
118 image {
119 width: 630rpx;
120 height: 300rpx;
121 }
122
123 .info {
124 position: absolute;
125 color: #fff;
126 top: 0;
127 width: 100%;
128 height: 100%;
129 padding: 30rpx 40rpx;
130 overflow: hidden;
131 box-sizing: border-box;
132
133 .name {
134 font-size: 34rpx;
135 color: #fff;
136 padding-bottom: 20rpx;
137 margin-bottom: 20rpx;
138 border-bottom: 1px solid RGBA(255, 255, 255, 0.7);
139 }
140 }
141
142 .esp_2 {
143 font-size: 28rpx;
144 margin-bottom: 26rpx;
145 }
146
147 .timeblock {
148 background: rgba(27, 27, 27, 0.1);
149 border-radius: 25rpx;
150 font-size: 22rpx;
151 padding: 12rpx 17rpx;
152 display: inline-flex;
153 align-items: center;
154
155 image {
156 width: 28rpx;
157 height: 28rpx;
158 margin-left: 22rpx;
159 }
160 }
161
162 }
163
164 .list {
165 padding: 24rpx 0 0 24rpx;
166 overflow: hidden;
167 }
168
169 .item {
170 border-radius: 15rpx;
171 background: #fff;
172 width: 338rpx;
173 float: left;
174 margin: 0 24rpx 24rpx 0;
175
176 image {
177 height: 180rpx;
178 width: 100%;
179 }
180
181 .info {
182 padding: 20rpx 26rpx;
183 height: 100rpx;
184 box-sizing: border-box;
185
186 .tt {
187 font-size: 28rpx;
188 line-height: 36rpx;
189 }
190 }
191 }
192 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <view class="graybg">
3 <view v-if="formData.type=='0'">
4 <view v-html="formData.content" class="richContent"></view>
5 </view>
6 <view v-if="formData.type=='1'" class="formBox">
7 <view @click="clickImg">
8 <image style="width: 100%;height: 50vw;" mode="aspectFit" v-for="p in formData.picArr" :src="p"/>
9 </view>
10
11 <view v-if="formData.content2" v-html="formData.content2" class="richContent2"></view>
12
13 <uni-forms ref="baseForm" :modelValue="baseFormData">
14 <uni-forms-item label="姓名" required v-if="formData.fields.indexOf('0')>-1">
15 <uni-easyinput v-model="baseFormData.name" placeholder="请输入姓名" />
16 </uni-forms-item>
17 <uni-forms-item label="手机号" required v-if="formData.fields.indexOf('1')>-1">
18 <uni-easyinput v-model="baseFormData.telno" placeholder="请输入手机号" />
19 </uni-forms-item>
20 <uni-forms-item label="需求描述" required v-if="formData.fields.indexOf('2')>-1">
21 <uni-easyinput type="textarea" v-model="baseFormData.requirement" placeholder="请输入需求描述" />
22 </uni-forms-item>
23 </uni-forms>
24 <button type="primary" @click="submit">提交</button>
25 </view>
26 </view>
27
28 <uni-popup ref="alertPayOk" type="dialog">
29 <uni-popup-dialog type="success" confirmText="返回主页" content="提交成功" @confirm="goIndex">
30 </uni-popup-dialog>
31 </uni-popup>
32 </template>
33
34 <script setup>
35 import {
36 ref,getCurrentInstance
37 } from 'vue';
38 import {
39 onLoad,
40 onShow,onReady
41 } from '@dcloudio/uni-app';
42 import * as api from '@/common/api.js';
43 const { proxy } = getCurrentInstance()
44 const app = getApp();
45 const telNo = ref('');
46 const alertPayOk = ref(null);
47 const isActive = ref(null);
48 const formData = ref({})
49 const baseFormData = ref({})
50 const rules= ref({
51 name: {rules: [{required: true,errorMessage: '请输入姓名'}]},
52 telno: {rules: [{required: true,errorMessage: '请输入手机号'}]},
53 requirement: {rules: [{required: true,errorMessage: '请输入需求描述'}]},
54 })
55
56 onReady(()=>{
57 // 修改页头标题
58 uni.setNavigationBarTitle({
59 title: formData.value.name
60 });
61 })
62 onShow(() => {
63 formData.value = JSON.parse(app.globalData.venue.miniappCustConfig)
64 formData.value.picArr = formData.value.pics.split(',')
65 });
66
67 function goIndex() {
68 uni.redirectTo({
69 url: `/pages/index/index`
70 })
71 }
72 function submit(){
73 // 姓名
74 if((formData.value.fields.indexOf('0')>-1) && baseFormData.value.name==undefined){
75 uni.showToast({
76 title: '请输入姓名',
77 icon: 'none',
78 duration: 2000
79 });
80 return
81 }
82 // 手机号
83 if(formData.value.fields.indexOf('1')>-1&&baseFormData.value.telno==undefined){
84 uni.showToast({
85 title: '请输入手机号',
86 icon: 'none',
87 duration: 2000
88 });
89 return
90 }
91 // 需求描述
92 if(formData.value.fields.indexOf('2')>-1&&baseFormData.value.requirement==undefined){
93 uni.showToast({
94 title: '请输入需求描述',
95 icon: 'none',
96 duration: 2000
97 });
98 return
99 }
100
101
102
103 api.miniappData(baseFormData.value).then((res)=>{
104 baseFormData.value = []
105 alertPayOk.value.open()
106 })
107
108 }
109 function clickImg() {
110 uni.previewImage({
111 urls: formData.value.picArr,
112 // current: 0,
113 success: function(res) {
114 console.log('success', res)
115 },
116 fail: function(res) {
117 console.log('fail', res)
118 },
119 complete: function(res) {
120 console.log('complete', res)
121 }
122 })
123 }
124 </script>
125
126 <style scoped>
127 button{ font-size: 32rpx; background: linear-gradient(90deg, #00C176, #3ed89b);}
128 .richContent{padding: 40rpx 40rpx 100rpx;
129 line-height: 1.6;
130 background: #fff;}
131 .richContent2{padding: 0 0 40rpx;
132 line-height: 1.6;
133 background: #fff;}
134
135 .graybg {
136 background: #f7f8fa;
137 height: 100vh;
138 padding: 0 0 100rpx;
139 width: 100vw;
140 overflow: auto;
141 }
142
143 .whitebg {
144 background: #fff;
145 margin-top: 15rpx;
146 border-radius: 20rpx;
147 margin-bottom: 90rpx;
148 }
149
150 .payBtn {
151 width: 750rpx;
152 line-height: 90rpx;
153 height: 120rpx;
154 text-align: center;
155 background: #ff8124;
156 color: #ffffff;
157 font-size: 36rpx;
158 border-radius: 20rpx 20rpx 0px 0px;
159 position: fixed;
160 bottom: 0;
161 }
162
163 .uni-list-cell::after {
164 display: none;
165 }
166 .formBox{ background: #fff;
167 padding: 50rpx 40rpx;
168 margin: 0 30rpx;
169 border-radius: 20rpx;}
170 </style>
This diff could not be displayed because it is too large.
1 <template>
2 <view>
3 <zb-tab :activeStyle="{
4 fontWeight: 'bold',
5 transform: 'scale(1.1)'
6 }" lineColor='linear-gradient(90deg, #FF9D33, #F56E06);' :data="kindList" :scrollable="true" lineWidth='30rpx'
7 @change="getList" v-model="query.category"></zb-tab>
8 <view class="list">
9 <view class="item" v-for="n in list" :key="n.paperId" @click="goDetail(n)">
10 <image :src="config.baseUrl_api+n.images"></image>
11 <view class="info">
12 <view class="tt esp_2">{{n.paperName}}</view>
13 </view>
14 </view>
15 </view>
16 <view class="nodata" v-if="list.length==0">
17 <image mode="aspectFit" src="/static/nodata.png"></image>
18 </view>
19 </view>
20 </template>
21
22 <script setup>
23 import {
24 onLoad,
25 onShow
26 } from '@dcloudio/uni-app';
27 import config from '@/config.js';
28 import {
29 ref,
30 getCurrentInstance
31 } from 'vue';
32 import * as api from '@/common/api.js';
33 const list = ref([])
34 const kindList = ref([])
35 const kindId = ref(0)
36 const query = ref({
37 category: 2
38 })
39 onLoad((option) => {
40 if(option.kindId){
41 kindId.value = Number(option.kindId)
42 }
43 })
44 onShow(()=>{
45 init()
46 })
47 function init() {
48 uni.showLoading({
49 title:`加载中`
50 })
51 api.getClassifyList().then(res => {
52 kindList.value = res.data
53 query.value.category = kindId
54 getList()
55 })
56 }
57
58 function getList() {
59 console.log(query.value.category)
60 api.getPaperList(query.value).then(res => {
61 list.value = res.rows
62 uni.hideLoading()
63 })
64 }
65
66 function goDetail(item) {
67 let path = `/exam/booking?id=${item.paperId}`;
68 uni.navigateTo({
69 url: path
70 });
71
72 }
73 </script>
74
75 <style lang="scss" scoped>
76 .list {
77 padding: 24rpx 0 0 24rpx;
78 overflow: hidden;
79 }
80
81 .item {
82 border-radius: 15rpx;
83 background: #fff;
84 width: 338rpx;
85 float: left;
86 margin: 0 24rpx 24rpx 0;
87
88 image {
89 height: 180rpx;
90 width: 100%;
91 }
92
93 .info {
94 padding: 20rpx 26rpx;
95 height: 100rpx;
96 box-sizing: border-box;
97
98 .tt {
99 font-size: 28rpx;
100 line-height: 36rpx;
101 }
102 }
103 }
104 </style>
...\ No newline at end of file ...\ No newline at end of file
1 {
2 "appid": "wx5d51e8ed31bbdbb7",
3 "compileType": "miniprogram",
4 "libVersion": "3.0.0",
5 "packOptions": {
6 "ignore": [],
7 "include": []
8 },
9 "setting": {
10 "coverView": true,
11 "es6": true,
12 "postcss": true,
13 "minified": true,
14 "enhance": true,
15 "showShadowRootInWxmlPanel": true,
16 "packNpmRelationList": [],
17 "babelSetting": {
18 "ignore": [],
19 "disablePlugins": [],
20 "outputPath": ""
21 },
22 "condition": false
23 },
24 "condition": {},
25 "editorSetting": {
26 "tabIndent": "insertSpaces",
27 "tabSize": 2
28 }
29 }
...\ No newline at end of file ...\ No newline at end of file
1 {
2 "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 "projectname": "Venue",
4 "setting": {
5 "compileHotReLoad": true
6 }
7 }
...\ No newline at end of file ...\ No newline at end of file
1 @font-face {
2 font-family: "iconfont";
3 /* Project id 3873999 */
4 src: url('/static/font/iconfont.ttf') format('woff2'),
5 url('/static/font/iconfont.ttf') format('woff'),
6 url('/static/font/iconfont.ttf') format('truetype');
7 }
8
9 .iconfont {
10 font-family: "iconfont" !important;
11 font-size: 16px;
12 font-style: normal;
13 -webkit-font-smoothing: antialiased;
14 -moz-osx-font-smoothing: grayscale;
15 }
16
17 .icon-31dingwei:before {
18 content: "\e600";
19 }
20
21 .icon-ai253:before {
22 content: "\e6f1";
23 }
24
25 .icon-loufangfangzi:before {
26 content: "\e729";
27 }
No preview for this file type
No preview for this file type
1 /**
2 * 这里是uni-app内置的常用样式变量
3 *
4 * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
5 * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
6 *
7 */
8
9 /**
10 * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
11 *
12 * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
13 */
14
15 /* 颜色变量 */
16
17 /* 行为相关颜色 */
18 $uni-color-primary: #00C176;
19 $uni-color-success: #4cd964;
20 $uni-color-warning: #f0ad4e;
21 $uni-color-error: #dd524d;
22
23 /* 文字基本颜色 */
24 $uni-text-color:#333;//基本色
25 $uni-text-color-inverse:#fff;//反色
26 $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
27 $uni-text-color-placeholder: #808080;
28 $uni-text-color-disable:#c0c0c0;
29
30 /* 背景颜色 */
31 $uni-bg-color:#ffffff;
32 $uni-bg-color-grey:#f8f8f8;
33 $uni-bg-color-hover:#f1f1f1;//点击状态颜色
34 $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
35
36 /* 边框颜色 */
37 $uni-border-color:#c8c7cc;
38
39 /* 尺寸变量 */
40
41 /* 文字尺寸 */
42 $uni-font-size-sm:12px;
43 $uni-font-size-base:14px;
44 $uni-font-size-lg:16;
45
46 /* 图片尺寸 */
47 $uni-img-size-sm:20px;
48 $uni-img-size-base:26px;
49 $uni-img-size-lg:40px;
50
51 /* Border Radius */
52 $uni-border-radius-sm: 2px;
53 $uni-border-radius-base: 3px;
54 $uni-border-radius-lg: 6px;
55 $uni-border-radius-circle: 50%;
56
57 /* 水平间距 */
58 $uni-spacing-row-sm: 5px;
59 $uni-spacing-row-base: 10px;
60 $uni-spacing-row-lg: 15px;
61
62 /* 垂直间距 */
63 $uni-spacing-col-sm: 4px;
64 $uni-spacing-col-base: 8px;
65 $uni-spacing-col-lg: 12px;
66
67 /* 透明度 */
68 $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
69
70 /* 文章场景相关 */
71 $uni-color-title: #2C405A; // 文章标题颜色
72 $uni-font-size-title:20px;
73 $uni-color-subtitle: #555555; // 二级标题颜色
74 $uni-font-size-subtitle:26px;
75 $uni-color-paragraph: #3F536E; // 文章段落颜色
76 $uni-font-size-paragraph:15px;
1 ## 1.2.0(2021-11-19)
2 - 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
3 - 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
4 ## 1.1.7(2021-11-08)
5 - 优化 升级ui
6 - 修改 size 属性默认值调整为 small
7 - 修改 type 属性,默认值调整为 error,info 替换 default
8 ## 1.1.6(2021-09-22)
9 - 修复 在字节小程序上样式不生效的 bug
10 ## 1.1.5(2021-07-30)
11 - 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
12 ## 1.1.4(2021-07-29)
13 - 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
14 ## 1.1.3(2021-06-24)
15 - 优化 示例项目
16 ## 1.1.1(2021-05-12)
17 - 新增 组件示例地址
18 ## 1.1.0(2021-05-12)
19 - 新增 uni-badge 的 absolute 属性,支持定位
20 - 新增 uni-badge 的 offset 属性,支持定位偏移
21 - 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
22 - 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
23 - 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
24 ## 1.0.7(2021-05-07)
25 - 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
26 - 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
27 - 新增 uni-badge 属性 custom-style, 支持自定义样式
28 ## 1.0.6(2021-02-04)
29 - 调整为uni_modules目录规范
1 <template>
2 <view class="uni-badge--x">
3 <slot />
4 <text v-if="text" :class="classNames" :style="[badgeWidth, positionStyle, customStyle, dotStyle]"
5 class="uni-badge" @click="onClick()">{{displayValue}}</text>
6 </view>
7 </template>
8
9 <script>
10 /**
11 * Badge 数字角标
12 * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
13 * @tutorial https://ext.dcloud.net.cn/plugin?id=21
14 * @property {String} text 角标内容
15 * @property {String} size = [normal|small] 角标内容
16 * @property {String} type = [info|primary|success|warning|error] 颜色类型
17 * @value info 灰色
18 * @value primary 蓝色
19 * @value success 绿色
20 * @value warning 黄色
21 * @value error 红色
22 * @property {String} inverted = [true|false] 是否无需背景颜色
23 * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
24 * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
25 * @value rightTop 右上
26 * @value rightBottom 右下
27 * @value leftTop 左上
28 * @value leftBottom 左下
29 * @property {Array[number]} offset 距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
30 * @property {String} isDot = [true|false] 是否显示为一个小点
31 * @event {Function} click 点击 Badge 触发事件
32 * @example <uni-badge text="1"></uni-badge>
33 */
34
35 export default {
36 name: 'UniBadge',
37 emits: ['click'],
38 props: {
39 type: {
40 type: String,
41 default: 'error'
42 },
43 inverted: {
44 type: Boolean,
45 default: false
46 },
47 isDot: {
48 type: Boolean,
49 default: false
50 },
51 maxNum: {
52 type: Number,
53 default: 99
54 },
55 absolute: {
56 type: String,
57 default: ''
58 },
59 offset: {
60 type: Array,
61 default () {
62 return [0, 0]
63 }
64 },
65 text: {
66 type: [String, Number],
67 default: ''
68 },
69 size: {
70 type: String,
71 default: 'small'
72 },
73 customStyle: {
74 type: Object,
75 default () {
76 return {}
77 }
78 }
79 },
80 data() {
81 return {};
82 },
83 computed: {
84 width() {
85 return String(this.text).length * 8 + 12
86 },
87 classNames() {
88 const {
89 inverted,
90 type,
91 size,
92 absolute
93 } = this
94 return [
95 inverted ? 'uni-badge--' + type + '-inverted' : '',
96 'uni-badge--' + type,
97 'uni-badge--' + size,
98 absolute ? 'uni-badge--absolute' : ''
99 ].join(' ')
100 },
101 positionStyle() {
102 if (!this.absolute) return {}
103 let w = this.width / 2,
104 h = 10
105 if (this.isDot) {
106 w = 5
107 h = 5
108 }
109 const x = `${- w + this.offset[0]}px`
110 const y = `${- h + this.offset[1]}px`
111
112 const whiteList = {
113 rightTop: {
114 right: x,
115 top: y
116 },
117 rightBottom: {
118 right: x,
119 bottom: y
120 },
121 leftBottom: {
122 left: x,
123 bottom: y
124 },
125 leftTop: {
126 left: x,
127 top: y
128 }
129 }
130 const match = whiteList[this.absolute]
131 return match ? match : whiteList['rightTop']
132 },
133 badgeWidth() {
134 return {
135 width: `${this.width}px`
136 }
137 },
138 dotStyle() {
139 if (!this.isDot) return {}
140 return {
141 width: '10px',
142 height: '10px',
143 borderRadius: '10px'
144 }
145 },
146 displayValue() {
147 const {
148 isDot,
149 text,
150 maxNum
151 } = this
152 return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
153 }
154 },
155 methods: {
156 onClick() {
157 this.$emit('click');
158 }
159 }
160 };
161 </script>
162
163 <style lang="scss" scoped>
164 $uni-primary: #2979ff !default;
165 $uni-success: #4cd964 !default;
166 $uni-warning: #f0ad4e !default;
167 $uni-error: #dd524d !default;
168 $uni-info: #909399 !default;
169
170
171 $bage-size: 12px;
172 $bage-small: scale(0.8);
173
174 .uni-badge--x {
175 /* #ifdef APP-NVUE */
176 // align-self: flex-start;
177 /* #endif */
178 /* #ifndef APP-NVUE */
179 display: inline-block;
180 /* #endif */
181 position: relative;
182 }
183
184 .uni-badge--absolute {
185 position: absolute;
186 }
187
188 .uni-badge--small {
189 transform: $bage-small;
190 transform-origin: center center;
191 }
192
193 .uni-badge {
194 /* #ifndef APP-NVUE */
195 display: flex;
196 overflow: hidden;
197 box-sizing: border-box;
198 /* #endif */
199 justify-content: center;
200 flex-direction: row;
201 height: 20px;
202 line-height: 18px;
203 color: #fff;
204 border-radius: 100px;
205 background-color: $uni-info;
206 background-color: transparent;
207 border: 1px solid #fff;
208 text-align: center;
209 font-family: 'Helvetica Neue', Helvetica, sans-serif;
210 font-size: $bage-size;
211 /* #ifdef H5 */
212 z-index: 999;
213 cursor: pointer;
214 /* #endif */
215
216 &--info {
217 color: #fff;
218 background-color: $uni-info;
219 }
220
221 &--primary {
222 background-color: $uni-primary;
223 }
224
225 &--success {
226 background-color: $uni-success;
227 }
228
229 &--warning {
230 background-color: $uni-warning;
231 }
232
233 &--error {
234 background-color: $uni-error;
235 }
236
237 &--inverted {
238 padding: 0 5px 0 0;
239 color: $uni-info;
240 }
241
242 &--info-inverted {
243 color: $uni-info;
244 background-color: transparent;
245 }
246
247 &--primary-inverted {
248 color: $uni-primary;
249 background-color: transparent;
250 }
251
252 &--success-inverted {
253 color: $uni-success;
254 background-color: transparent;
255 }
256
257 &--warning-inverted {
258 color: $uni-warning;
259 background-color: transparent;
260 }
261
262 &--error-inverted {
263 color: $uni-error;
264 background-color: transparent;
265 }
266
267 }
268 </style>
1 {
2 "id": "uni-badge",
3 "displayName": "uni-badge 数字角标",
4 "version": "1.2.0",
5 "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
6 "keywords": [
7 "",
8 "badge",
9 "uni-ui",
10 "uniui",
11 "数字角标",
12 "徽章"
13 ],
14 "repository": "https://github.com/dcloudio/uni-ui",
15 "engines": {
16 "HBuilderX": ""
17 },
18 "directories": {
19 "example": "../../temps/example_temps"
20 },
21 "dcloudext": {
22 "category": [
23 "前端组件",
24 "通用组件"
25 ],
26 "sale": {
27 "regular": {
28 "price": "0.00"
29 },
30 "sourcecode": {
31 "price": "0.00"
32 }
33 },
34 "contact": {
35 "qq": ""
36 },
37 "declaration": {
38 "ads": "无",
39 "data": "无",
40 "permissions": "无"
41 },
42 "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
43 },
44 "uni_modules": {
45 "dependencies": [],
46 "encrypt": [],
47 "platforms": {
48 "cloud": {
49 "tcb": "y",
50 "aliyun": "y"
51 },
52 "client": {
53 "App": {
54 "app-vue": "y",
55 "app-nvue": "y"
56 },
57 "H5-mobile": {
58 "Safari": "y",
59 "Android Browser": "y",
60 "微信浏览器(Android)": "y",
61 "QQ浏览器(Android)": "y"
62 },
63 "H5-pc": {
64 "Chrome": "y",
65 "IE": "y",
66 "Edge": "y",
67 "Firefox": "y",
68 "Safari": "y"
69 },
70 "小程序": {
71 "微信": "y",
72 "阿里": "y",
73 "百度": "y",
74 "字节跳动": "y",
75 "QQ": "y"
76 },
77 "快应用": {
78 "华为": "y",
79 "联盟": "y"
80 },
81 "Vue": {
82 "vue2": "y",
83 "vue3": "y"
84 }
85 }
86 }
87 }
88 }
...\ No newline at end of file ...\ No newline at end of file
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!