This commit is contained in:
王创世 2025-08-07 17:53:23 +08:00
parent ed01d833b9
commit af094e55b0
12 changed files with 2404 additions and 1100 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/unpackage
/.hbuilderx
.history

View File

@ -5,6 +5,9 @@ const api_prefix = api_host + '/addons/exam/'
//工具类
module.exports = {
apiUrlReturn(){
return api_host;
},
isShowTip(apiUrl) {
let filterList = ['/agency/getAuditVersion']
if (filterList.indexOf(apiUrl) != -1) {

File diff suppressed because it is too large Load Diff

View File

@ -95,7 +95,7 @@
}, {
"path": "pages/train/index",
"style": {
"navigationBarTitleText": "题目选择",
"navigationBarTitleText": "平台题库",
"enablePullDownRefresh": false
}
@ -106,6 +106,13 @@
"enablePullDownRefresh": false
}
}, {
"path": "pages/train/detail",
"style": {
"navigationBarTitleText": "题目选择",
"enablePullDownRefresh": false
}
}, {
"path": "pages/webview/webview",
"style": {
@ -142,7 +149,7 @@
}, {
"path": "pages/index/news-detail",
"style": {
"navigationBarTitleText": "详情",
"navigationBarTitleText": "关于我们",
"enablePullDownRefresh": false
}
}, {
@ -219,6 +226,11 @@
"navigationBarTitleText": "科目",
"enablePullDownRefresh": true
}
},{
"path": "sign_up",
"style": {
"navigationBarTitleText": "预约报名"
}
},
{
"path": "video/index",

View File

@ -14,18 +14,17 @@
我们的位置
</view>
<view class="mapContainer">
<map
:latitude="mapData.latitude"
:longitude="mapData.longitude"
:markers="mapData.markers"
:scale="mapData.scale"
:show-location="true"
@markertap="handleMarkerTap"
@callouttap="handleCalloutTap"
class="map"
></map>
<map :latitude="mapData.latitude" :longitude="mapData.longitude" :markers="mapData.markers"
:scale="mapData.scale" :show-location="true" @markertap="handleMarkerTap"
@callouttap="handleCalloutTap" class="map"></map>
</view>
</view>
<view style="padding-bottom: 30rpx;margin-top: 50rpx;">
<tn-button fontColor="#ffffff" type="primary" width="100%" height="88rpx" @click="openBm"
:loading="submitting" backgroundColor="#1A73E8">
预约报名
</tn-button>
</view>
</view>
<!-- <view class="cu-bar justify-left bg-white margin-top-sm">
@ -48,6 +47,7 @@
<text class="text-df" style="margin-top: 2rpx;">{{newsData.commentNum}}</text>
</view>
</view> -->
</view>
<!-- <view class="cu-bar bg-white tabbar border shop bottomBox">
@ -68,164 +68,170 @@
</template>
<script>
import newsApi from "@/common/api/news.js"
import newsApi from "@/common/api/news.js"
export default {
data() {
return {
newsData: [],
requestStatus: false, //
tagStyle: {
table: 'border: 1px solid gray;border-collapse:collapse',
th: 'border: 1px solid gray;',
td: 'border: 1px solid gray;'
},
//
mapData: {
latitude: 34.621881, //
longitude: 112.436631, //
scale: 17, //
markers: [{
id: 1,
latitude: 34.621881,
longitude: 112.436631,
title: '名扬体育学院',
width:15,
height:20,
callout: {
content: '名扬体育学院',
color: '#000000',
fontSize: 14,
borderRadius: 8,
bgColor: '#ffffff',
padding: 8,
display: 'ALWAYS'
}
}]
export default {
data() {
return {
newsData: [],
requestStatus: false, //
tagStyle: {
table: 'border: 1px solid gray;border-collapse:collapse',
th: 'border: 1px solid gray;',
td: 'border: 1px solid gray;'
},
//
mapData: {
latitude: 34.621881, //
longitude: 112.436631, //
scale: 17, //
markers: [{
id: 1,
latitude: 34.621881,
longitude: 112.436631,
title: '名扬体育学院',
width: 15,
height: 20,
callout: {
content: '名扬体育学院',
color: '#000000',
fontSize: 14,
borderRadius: 8,
bgColor: '#ffffff',
padding: 8,
display: 'ALWAYS'
}
}]
}
}
},
onLoad(option) {
console.log(option)
this.getData(option.id);
},
methods: {
//
getData(id) {
console.log(id);
newsApi.getNewsDetail(this, {
id: id
}).then(res => {
s
if (res && res.data) {
this.newsData = res.data
}
})
},
//
openNavigation() {
uni.openLocation({
latitude: this.mapData.latitude,
longitude: this.mapData.longitude,
name: '名扬体育学院',
address: '名扬体育学院',
scale: 18,
success: () => {
console.log('成功打开地图导航');
},
fail: (err) => {
console.error('打开地图导航失败', err);
uni.showToast({
title: '打开地图失败',
icon: 'none'
});
}
});
},
//
handleMarkerTap(e) {
console.log('标记点被点击', e);
this.openNavigation();
},
// callout
handleCalloutTap(e) {
console.log('callout被点击', e);
this.openNavigation();
},
handleBack() {
this.utils.goto('news-list')
},
handleGo() {
if (this.newsData && this.newsData.front_info) {
this.utils.goto(this.newsData.front_info.full_url)
}
},
onLoad(option) {
console.log(option)
this.getData(option.id);
openBm() {
uni.navigateTo({
url: '/pagesSubject/sign_up'
})
},
methods: {
//
getData(id) {
console.log(id);
newsApi.getNewsDetail(this, {
id: id
}).then(res => {
if (res && res.data) {
this.newsData = res.data
}
})
},
//
openNavigation() {
uni.openLocation({
latitude: this.mapData.latitude,
longitude: this.mapData.longitude,
name: '名扬体育学院',
address: '名扬体育学院',
scale: 18,
success: () => {
console.log('成功打开地图导航');
},
fail: (err) => {
console.error('打开地图导航失败', err);
uni.showToast({
title: '打开地图失败',
icon: 'none'
});
}
});
},
//
handleMarkerTap(e) {
console.log('标记点被点击', e);
this.openNavigation();
},
// callout
handleCalloutTap(e) {
console.log('callout被点击', e);
this.openNavigation();
},
handleBack() {
this.utils.goto('news-list')
},
handleGo() {
if (this.newsData && this.newsData.front_info) {
this.utils.goto(this.newsData.front_info.full_url)
}
},
previewImage(index) {
// uniapppreviewImage
const seeImgList = this.newsData.images
uni.previewImage({
current: index, //
urls: seeImgList //
})
},
previewImage(index) {
// uniapppreviewImage
const seeImgList = this.newsData.images
uni.previewImage({
current: index, //
urls: seeImgList //
})
},
}
},
}
</script>
<style lang="scss" scoped>
button::after {
border: none;
background: transparent;
}
button::after {
border: none;
background: transparent;
}
uni-button {
background: transparent;
}
uni-button {
background: transparent;
}
.container {
background-color: #f2f2f2;
}
.container {
background-color: #f2f2f2;
}
.solid {
border-radius: 50rpx;
text-indent: 12rpx;
}
.solid {
border-radius: 50rpx;
text-indent: 12rpx;
}
image {
width: 750rpx;
}
image {
width: 750rpx;
}
.bottomBox {
width: 750rpx;
position: fixed;
left: 0;
bottom: 0rpx;
}
.bottomBox {
width: 750rpx;
position: fixed;
left: 0;
bottom: 0rpx;
}
/* 地图相关样式 */
.mapSection {
background-color: #FFFFFF;
margin-top: 20rpx;
border-radius: 16rpx;
}
/* 地图相关样式 */
.mapSection {
background-color: #FFFFFF;
margin-top: 20rpx;
border-radius: 16rpx;
}
.mapTitle {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.mapTitle {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.mapContainer {
width: 100%;
height: 400rpx;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.mapContainer {
width: 100%;
height: 400rpx;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.map {
width: 100%;
height: 100%;
}
.map {
width: 100%;
height: 100%;
}
</style>

136
pages/train/detail.vue Normal file
View File

@ -0,0 +1,136 @@
<template>
<view style="padding: 30rpx; background-color: #FAFAFA; min-height: 100vh;">
<view style="display: flex;align-items: center;">
<view @click="show = true"
style="display: flex;align-items: center; border: 2rpx solid #1A73E8; border-radius: 32rpx; padding: 8rpx 24rpx; color: #1A73E8; background: #fff; font-weight: 500; box-shadow: 0 2rpx 8rpx rgba(26,115,232,0.08); cursor: pointer; transition: background 0.2s;">
<view style="margin-right: 8rpx;">更多题库</view>
<view>
<text class="tn-icon-down-triangle"
style="font-size: 24rpx; color: #1A73E8; position: relative;"></text>
</view>
</view>
<view style="display: inline-block; position: relative;padding-left: 30rpx;font-size: 32rpx;font-weight: bold;">
<text>{{ info.text }}</text>
</view>
</view>
<view style="padding: 20rpx 0px;margin-top: 30rpx;">
<view v-for="item in info.children" style="margin-bottom: 40rpx;">
<view @click="goTrain(item.value, item.text, item.type)"
style="display: flex;justify-content: space-between;align-items: center; background: #fff; border-radius: 16rpx; box-shadow: 0 4rpx 16rpx rgba(26,115,232,0.06); padding: 30rpx;">
<view style="display: flex;align-items: center;">
<view
style="height: 40rpx;width: 40rpx;background-color: #1A73E8;border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 24rpx; font-weight: bold;">
</view>
<view style="padding-left: 32rpx;">
<view style="font-size: 32rpx; font-weight: bold; color: #222;">{{ item.text }}</view>
<view style="color: #999999;font-size: 24rpx;padding-top: 8rpx;">题目数量{{ item.count }}
</view>
</view>
</view>
<!-- 1会员 2不是会员 -->
<view v-if="item.type == 2"
style="background: #1A73E8; color: #fff; border-radius: 24rpx; padding: 4rpx 28rpx; font-size: 26rpx; font-weight: 500; letter-spacing: 2rpx;">
免费</view>
<view v-else
style="background: #f39c12; color: #fff; border-radius: 24rpx; padding: 4rpx 28rpx; font-size: 26rpx; font-weight: 500; letter-spacing: 2rpx;">
会员</view>
</view>
</view>
</view>
<tn-popup v-model="show" mode="left" width="550rpx"
:style="'border-radius:32rpx 0 0 32rpx; box-shadow: 0 8rpx 32rpx rgba(26,115,232,0.12); overflow: hidden;'">
<view style="padding: 30rpx;">
<view v-for="item in cateList" @click="getTree(item)"
style="margin-bottom: 40rpx;padding:25rpx 20rpx;text-align: center;background-color: #F3F5F7;border-radius: 60rpx; font-size: 28rpx; color: #1A73E8;">
{{ item.text }}</view>
</view>
</tn-popup>
</view>
</template>
<script>
import newsApi from "@/common/api/news.js"
export default {
data() {
return {
show: false,
id: 0,
cateList: [],
info: {},
vip: 0,
}
},
onLoad(op) {
console.log(op);
this.id = op.id;
this.getCate();
this.getIsUser();
},
methods: {
getTree(item) {
this.info = item;
this.show = false;
},
getIsUser() {
newsApi.ifUserMember(this, {}).then(res => {
//0
console.log(res);
this.vip = res.code;
})
},
getCate() {
this.http('cate/getThree', {
kind: 'QUESTION',
}).then(res => {
this.cateList = res.data;
this.info = res.data.find(item => item.value == this.id);
})
},
goTrain(id, name, type) {
if (type == 1 && this.vip == 0) {
uni.showModal({
title: '提示',
content: '该题库仅限会员可用,请联系客服开通会员!',
confirmText: '联系客服',
success: (res) => {
if (res.confirm) {
uni.makePhoneCall({
phoneNumber: '18903795988' //
});
}
}
});
return;
}
this.utils.goto('train?cateId=' + id + '&cateName=' + name + '&mode=normal')
}
}
}
</script>
<style>
page {
background-color: #FAFAFA;
}
/* 统一字体和颜色 */
body,
view,
text {
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
color: #222;
}
/* 主题色变量可用于后续扩展 */
:root {
--theme-color: #1A73E8;
}
/* 适当增加全局间距 */
view {
box-sizing: border-box;
}
/* 注释:如需进一步美化可在此扩展 */
</style>

View File

@ -3,8 +3,8 @@
<!-- <view class="card-view">
<image :src="bannerImage" mode="aspectFill" style="width: 100%; height: 200rpx;"></image>
</view> -->
<view style="height:99vh">
<view class="card-view" style="height: 85%;">
<view>
<view>
<!-- <tui-divider width="80%" gradual>选择要练习的题目类型</tui-divider>
<view class="margin">
<tn-radio-group activeColor="#1A73E8" v-model="mode">
@ -20,13 +20,34 @@
<view v-if="mode == 'random'">* 随机出题不记忆当前做题题标</view>
</view> -->
<tui-cascade-selection height="75vh" :itemList="cateList" @complete="complete" text="请选择题库"
<!-- <tui-cascade-selection height="75vh" :itemList="cateList" @complete="complete" text="请选择题库"
:defaultItemList="defaultCateList"></tui-cascade-selection>
</view>
<view style="width:90%; margin: 10rpx auto;" class="padding-bottom-xl">
<tui-button shape="circle" shadow bold preventClick :disabled="questionCount == 0"
@click="checkPay">{{btnText}}</tui-button>
</view> -->
<view class="tn-margin-top-sm">
<view class="tn-flex tn-flex-wrap tn-margin-sm">
<block v-for="(item, index) in cateList" :key="index">
<view style="width: 50%">
<view class="question-bank-card tn-margin-xs"
@click="checkPay(item.value)">
<view class="question-bank-image-wrapper">
<image class="question-bank-image" :src="imgUrl + item.image" mode="aspectFill">
</image>
</view>
<view class="question-bank-title">
{{ item.text }}
</view>
</view>
</view>
</block>
</view>
</view>
</view>
</view>
@ -42,130 +63,58 @@
</template>
<script>
import cateApi from "@/common/api/cate.js"
export default {
data() {
return {
page: '',
cateList: [],
cateId: 0,
cateName: '',
questionCount: 0,
btnText: '开始练习',
mode: 'normal',
defaultCateList: [],
import cateApi from "@/common/api/cate.js"
export default {
data() {
return {
//
imgUrl: this.imgUrl,
page: '',
cateList: [],
cateId: 0,
cateName: '',
questionCount: 0,
btnText: '开始练习',
mode: 'normal',
defaultCateList: [],
//
catePrice: 0.00,
showCateConfirm: false,
confirmCateContent: '',
//
catePrice: 0.00,
showCateConfirm: false,
confirmCateContent: '',
subjectId: 0,
subjectId: 0,
bannerImage: '',
bannerImage: '',
}
},
onLoad(e) {
this.page = e?.page
this.getPageCache()
this.subjectId = this.utils.getSubjectId()
this.getCate()
},
methods: {
//
getPageCache() {
let cdn_url = this.utils.getData('cdn_url')
cdn_url = cdn_url ? cdn_url : ''
let pageCache = this.utils.getData('page')
console.log('pageCache', pageCache)
if (pageCache && pageCache.cate_banner_image) {
this.bannerImage = cdn_url + pageCache.cate_banner_image
console.log('this.bannerImage', this.bannerImage)
}
},
onLoad(e) {
this.page = e?.page
this.getPageCache()
this.subjectId = this.utils.getSubjectId()
this.getCate()
},
methods: {
//
getPageCache() {
let cdn_url = this.utils.getData('cdn_url')
cdn_url = cdn_url ? cdn_url : ''
let pageCache = this.utils.getData('page')
console.log('pageCache', pageCache)
if (pageCache && pageCache.cate_banner_image) {
this.bannerImage = cdn_url + pageCache.cate_banner_image
console.log('this.bannerImage', this.bannerImage)
}
},
//
getCate() {
this.http('cate/getThree', {
kind: 'QUESTION',
page: this.page,
subject_id: this.subjectId
}).then(res => {
this.cateList = res.data
//
if (this.cateId) {
this.complete({
value: this.cateId,
result: [{
text: this.cateName
}]
})
} else {
let defaultCate = this.utils.getData('default_cate-QUESTION')
console.log('defaultCate', defaultCate)
if (defaultCate) {
let lastCate = [...defaultCate.result].pop()
console.log('lastCate', lastCate)
let hasCate = false
for (let j = 0; j < this.cateList.length; j++) {
let cate = this.cateList[j]
if (hasCate || cate.value == lastCate.value) {
hasCate = true
break
}
if (cate.children && cate.children.length > 0) {
for (let k = 0; k < cate.children.length; k++) {
let child_cate = cate.children[k]
if (child_cate.value == lastCate.value) {
hasCate = true
break
}
}
}
}
if (hasCate) {
let defaultCateList = []
for (let i = 0; i < defaultCate.result.length; i++) {
defaultCateList.push(defaultCate.result[i].text)
}
this.defaultCateList = defaultCateList
this.cateId = lastCate.value
this.cateName = lastCate.text
this.complete({
value: this.cateId,
result: [{
text: this.cateName
}]
})
}
}
// let user = this.utils.getData('user')
// if (user?.info && user.info?.default_cate_ids) {
// this.defaultCateList = [...user.info.default_cate_names]
// this.cateId = [...user.info.default_cate_ids].pop()
// this.cateName = [...user.info.default_cate_names].pop()
// this.complete({
// value: this.cateId,
// result: [
// {
// text: this.cateName
// }
// ]
// })
// }
}
// this.defaultCateList = ["","",]
})
//
getCate() {
this.http('cate/getThree', {
kind: 'QUESTION',
page: this.page,
subject_id: this.subjectId
}).then(res => {
this.cateList = res.data
//
if (this.cateId) {
@ -175,105 +124,216 @@
text: this.cateName
}]
})
}
},
//
complete(e) {
console.log(e);
console.log('您选择的数据为:', e);
} else {
let defaultCate = this.utils.getData('default_cate-QUESTION')
console.log('defaultCate', defaultCate)
if (defaultCate) {
let lastCate = [...defaultCate.result].pop()
console.log('lastCate', lastCate)
this.cateId = e.value
this.cateName = e.result[e.result.length - 1].text
let hasCate = false
for (let j = 0; j < this.cateList.length; j++) {
let cate = this.cateList[j]
if (hasCate || cate.value == lastCate.value) {
hasCate = true
break
}
let params = {
cate_id: this.cateId,
just_get_count: 1,
}
this.$refs.login.afterMethod = () => {
this.complete(e)
}
console.log('afterMethod', this.$refs.login.afterMethod)
this.http('question/train', params).then(res => {
if (res.code == 1) {
this.questionCount = res.data.total
if (this.questionCount) {
this.btnText = '开始练习'
} else {
this.btnText = '当前分类无试题'
}
} else {
this.utils.toast(res.msg)
}
})
},
//
checkPay() {
if (!this.cateId) {
this.utils.toast('请先选择练习的题库')
return
}
//
cateApi.checkPay(this, this.cateId).then(res => {
console.log('checkPay res', res)
if (res.code != 1) {
// this.utils.toast(res.msg)
// if (res.data.need_open_member) {
// this.utils.goto('/pages/user/member-center')
// }
uni.showModal({
title: '提示',
content: res.msg,
confirmText: '联系客服',
success: (res) => {
if (res.confirm) {
//this.utils.goto('/pages/user/member-center?from_train=1')
uni.makePhoneCall({
phoneNumber: '18903795988' //
});
} else if (res.cancel) {
this.utils.goback()
if (cate.children && cate.children.length > 0) {
for (let k = 0; k < cate.children.length; k++) {
let child_cate = cate.children[k]
if (child_cate.value == lastCate.value) {
hasCate = true
break
}
}
}
});
return
}
if (hasCate) {
let defaultCateList = []
for (let i = 0; i < defaultCate.result.length; i++) {
defaultCateList.push(defaultCate.result[i].text)
}
this.defaultCateList = defaultCateList
this.cateId = lastCate.value
this.cateName = lastCate.text
this.complete({
value: this.cateId,
result: [{
text: this.cateName
}]
})
}
}
//
if (res.data.status == 1) {
this.goTrain()
return
} else if (res.data.status == 2) {
this.catePrice = parseFloat(res.data.price)
this.confirmCateContent = res.data.msg
this.showCateConfirm = true
}
// let user = this.utils.getData('user')
// if (user?.info && user.info?.default_cate_ids) {
// this.defaultCateList = [...user.info.default_cate_names]
// this.cateId = [...user.info.default_cate_ids].pop()
// this.cateName = [...user.info.default_cate_names].pop()
// this.complete({
// value: this.cateId,
// result: [
// {
// text: this.cateName
// }
// ]
// })
// }
}
// this.defaultCateList = ["","",]
})
//
if (this.cateId) {
this.complete({
value: this.cateId,
result: [{
text: this.cateName
}]
})
},
//
goTrain() {
this.showCateConfirm = false
this.showResult = false
this.confirmCateContent = ''
this.payResultContent = ''
this.page = this.page == 'train' ? 'train' : 'look'
this.utils.goto(this.page + '?cateId=' + this.cateId + '&cateName=' + this.cateName + '&mode=' + this.mode)
},
closeDialog() {
console.log('get emit closeDialog')
this.showCateConfirm = false
}
},
//
complete(e) {
console.log(e);
console.log('您选择的数据为:', e);
this.cateId = e.value
this.cateName = e.result[e.result.length - 1].text
let params = {
cate_id: this.cateId,
just_get_count: 1,
}
this.$refs.login.afterMethod = () => {
this.complete(e)
}
console.log('afterMethod', this.$refs.login.afterMethod)
this.http('question/train', params).then(res => {
if (res.code == 1) {
this.questionCount = res.data.total
if (this.questionCount) {
this.btnText = '开始练习'
} else {
this.btnText = '当前分类无试题'
}
} else {
this.utils.toast(res.msg)
}
})
},
//
checkPay(cateId) {
// if (!this.cateId) {
// this.utils.toast('')
// return
// }
//
cateApi.checkPay(this, cateId).then(res => {
console.log('checkPay res', res)
if (res.code != 1) {
// this.utils.toast(res.msg)
// if (res.data.need_open_member) {
// this.utils.goto('/pages/user/member-center')
// }
uni.showModal({
title: '提示',
content: res.msg,
confirmText: '联系客服',
success: (res) => {
if (res.confirm) {
//this.utils.goto('/pages/user/member-center?from_train=1')
uni.makePhoneCall({
phoneNumber: '18903795988' //
});
} else if (res.cancel) {
this.utils.goback()
}
}
});
return
}
if (res.data.status == 1) {
this.utils.goto('/pages/train/detail?id=' + cateId);
return
}
//
// if (res.data.status == 1) {
// this.goTrain()
// return
// } else if (res.data.status == 2) {
// this.catePrice = parseFloat(res.data.price)
// this.confirmCateContent = res.data.msg
// this.showCateConfirm = true
// }
})
},
//
goTrain() {
this.showCateConfirm = false
this.showResult = false
this.confirmCateContent = ''
this.payResultContent = ''
this.page = this.page == 'train' ? 'train' : 'look'
this.utils.goto(this.page + '?cateId=' + this.cateId + '&cateName=' + this.cateName + '&mode=' + this.mode)
},
closeDialog() {
console.log('get emit closeDialog')
this.showCateConfirm = false
}
}
}
</script>
<style>
.tn-radio__label {
color: #333 !important;
font-size: 15px !important;
page {
background-color: #fff;
}
.tn-radio__label {
color: #333 !important;
font-size: 15px !important;
}
/* 题库卡片样式 start */
.question-bank-card {
background-color: #ffffff;
border-radius: 15rpx;
}
.question-bank-card:active {
transform: scale(0.98);
}
.question-bank-image-wrapper {
width: 100%;
height: 200rpx;
overflow: hidden;
border-radius: 15rpx;
}
.question-bank-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.question-bank-title {
padding: 15rpx;
font-size: 32rpx;
color: #333333;
display: flex;
}
/* 题库卡片样式 end */
</style>

View File

@ -6,6 +6,7 @@
<!-- toast提示 -->
<tui-toast ref="toast"></tui-toast>
<login ref="login" v-on:succ="ajax"></login>
</view>
</template>
@ -30,6 +31,9 @@ export default {
this.getQuestion()
},
methods: {
ajax(){
this.getQuestion()
},
//
getQuestion (page = 1, callback = null) {
console.log('getQuestion', page, this.currentPage, this.lastPage)

953
pagesSubject/sign_up.vue Normal file
View File

@ -0,0 +1,953 @@
<template>
<view class="container">
<view class="form-container">
<tn-form ref="form" :model="form" :errorType="errorType" :labelPosition="labelPosition"
:labelWidth="labelWidth" :labelAlign="labelAlign" :borderBottom="false">
<!-- 姓名 -->
<tn-form-item label="姓名" prop="name" class="form-item-vertical" required>
<tn-input v-model="form.name" type="text" placeholder="请输入姓名" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 性别 -->
<tn-form-item label="性别" prop="sex" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.sex" direction="row">
<tn-radio name="男" style="margin-right: 40rpx;"></tn-radio>
<tn-radio name="女"></tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 身份证号 -->
<tn-form-item label="身份证号" prop="code" class="form-item-vertical" required>
<tn-input v-model="form.code" type="text" placeholder="请输入身份证号" :border="false"
:placeholderStyle="placeholderStyle" maxlength="18" />
</tn-form-item>
<!-- 出生日期 -->
<tn-form-item label="出生日期" prop="userymd" class="form-item-vertical" required @click="showDatePicker">
<view class="date-picker-wrapper" @click="showDatePicker">
<tn-input @click="showDatePicker" v-model="form.userymd" type="text" placeholder="请选择出生日期"
:border="false" :placeholderStyle="placeholderStyle" :disabled="true" />
<view class="picker-icon">
<text class="tn-icon-calendar"></text>
</view>
</view>
</tn-form-item>
<!-- 联系电话 -->
<tn-form-item label="手机号码" prop="phone" class="form-item-vertical" required>
<tn-input v-model="form.phone" type="number" placeholder="请输入手机号码" :border="false"
:placeholderStyle="placeholderStyle" maxlength="11" @blur="validatePhone" />
</tn-form-item>
<!-- 上传蓝底电子版照片 -->
<tn-form-item label="蓝底电子版照片" prop="oneimage" class="form-item-vertical" required>
<view class="upload-new-wrapper">
<view class="upload-status">
<view class="upload-status-text">
<text v-if="form.imageFile">文件选择成功</text>
<text v-if="form.imageFile" class="preview-link" @click="previewImage">点击预览</text>
<text v-if="!form.imageFile">请选择图片文件</text>
</view>
<text style="color: #E5E5E5;">|</text>
<view class="upload-btn" @click="chooseImage">
<text class="upload-btn-text">{{ form.imageFile ? '重新选择' : '选择文件' }}</text>
</view>
</view>
</view>
</tn-form-item>
<!-- 报考科目 -->
<tn-form-item label="报考科目" prop="kemu" class="form-item-vertical" required>
<view class="subject-tags">
<view v-for="subject in subjectOptions" :key="subject.value" class="subject-tag"
:class="{ 'subject-tag--selected': form.kemu.includes(subject.value) }"
@click="toggleSubject(subject.value)">
<text>{{ subject.label }}</text>
<view v-if="form.kemu.includes(subject.value)" class="subject-tag__check">
<text class="tn-icon-success"></text>
</view>
</view>
</view>
</tn-form-item>
<!-- 报考级别 -->
<tn-form-item label="报考级别" prop="jibie" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.jibie" direction="row">
<tn-radio v-for="level in levelOptions" :key="level.value" :name="level.value"
style="margin-right: 40rpx;">
{{ level.label }}
</tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 报考类型 -->
<tn-form-item label="报考类型" prop="type" class="form-item-vertical" required>
<view class="exam-type-tags">
<view v-for="type in examTypeOptions" :key="type.value" class="exam-type-tag"
:class="{ 'exam-type-tag--selected': form.type.includes(type.value) }"
@click="toggleExamType(type.value)">
<text>{{ type.label }}</text>
<view v-if="form.type.includes(type.value)" class="exam-type-tag__check">
<text class="tn-icon-success"></text>
</view>
</view>
</view>
</tn-form-item>
<!-- 毕业学校 -->
<tn-form-item label="毕业学校" prop="by_school" class="form-item-vertical" required>
<tn-input v-model="form.by_school" type="text" placeholder="请输入毕业学校" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 毕业专业 -->
<tn-form-item label="毕业专业" prop="by_zy" class="form-item-vertical" required>
<tn-input v-model="form.by_zy" type="text" placeholder="请输入毕业专业" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 最高学历 -->
<tn-form-item label="最高学历" prop="zgxl" class="form-item-vertical" required>
<tn-radio-group activeColor="#1A73E8" :size="43" v-model="form.zgxl" direction="row">
<tn-radio v-for="edu in educationOptions" :key="edu.value" :name="edu.value">{{ edu.label
}}</tn-radio>
</tn-radio-group>
</tn-form-item>
<!-- 工作单位 -->
<tn-form-item label="工作单位" prop="danwei" class="form-item-vertical" required>
<tn-input v-model="form.danwei" type="text" placeholder="请输入工作单位" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 累计从事本职业时间 -->
<tn-form-item label="累计从事本职业时间" prop="leijishijian" class="form-item-vertical" required>
<tn-input v-model="form.leijishijian" type="text" placeholder="请输入累计从事本职业时间" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
<!-- 培训基地 -->
<tn-form-item label="培训基地" prop="pxjd" class="form-item-vertical" required>
<tn-input v-model="form.pxjd" type="text" placeholder="请输入培训基地" :border="false"
:placeholderStyle="placeholderStyle" />
</tn-form-item>
</tn-form>
<!-- 提交按钮 -->
<view class="submit-section">
<tn-button fontColor="#ffffff" type="primary" width="100%" height="88rpx" @click="submitForm"
:loading="submitting" backgroundColor="#1A73E8">
马上提交
</tn-button>
</view>
<!-- 用户协议同意 -->
<view class="agreement-section">
<view>
<tn-checkbox-group activeColor="#1A73E8" :size="43" v-model="agreementChecked">
<tn-checkbox name="agree" class="agreement-checkbox"></tn-checkbox>
</tn-checkbox-group>
</view>
<view class="agreement-content">
<text class="agreement-text">我已阅读并同意</text>
<text class="agreement-link" @click="openUserAgreement">用户服务协议</text>
<text class="agreement-text"></text>
<text class="agreement-link" @click="openPrivacyPolicy">隐私政策</text>
</view>
</view>
</view>
<!-- 日期选择器 -->
<tn-picker v-model="datePickerShow" mode="time" :params="dateParams" @confirm="onDateConfirm"
@cancel="datePickerShow = false"></tn-picker>
<login ref="login" v-on:succ="ajax()"></login>
</view>
</template>
<script>
export default {
data() {
return {
TimeShow: false,
//
form: {
name: '', //
sex: '', //
code: '', //
userymd: '', //
phone: '', //
oneimage: '', // URL
imageFile: null, //
kemu: [], //
jibie: '', //
type: [], //
by_school: '', //
by_zy: '', //
zgxl: '', //
danwei: '', //
leijishijian: '', //
pxjd: '' //
},
//
errorType: ['toast'],
labelPosition: 'top',
labelWidth: 120,
labelAlign: 'left',
placeholderStyle: 'color: #999; font-size: 28rpx;',
//
datePickerShow: false,
dateParams: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
//
submitting: false,
//
agreementChecked: [],
//
subjectOptions: [
{ label: '游泳救生员', value: '游泳救生员' },
{ label: '游泳社会体育指导员', value: '游泳社会体育指导员' },
{ label: '健身教练', value: '健身教练' },
{ label: '水质管理员', value: '水质管理员' },
{ label: '潜水', value: '潜水' },
{ label: '滑雪', value: '滑雪' },
{ label: '少儿体适能', value: '少儿体适能' }
],
levelOptions: [
{ label: '初级(五级)', value: '初级(五级)' },
{ label: '中级(四级)', value: '中级(四级)' },
{ label: '高级(三级)', value: '高级(三级)' }
],
examTypeOptions: [
{ label: '正常', value: '正常' },
{ label: '补考理论', value: '补考理论' },
{ label: '补考实操', value: '补考实操' },
{ label: '补考双项', value: '补考双项' }
],
educationOptions: [
{ label: '博士', value: '博士' },
{ label: '硕士', value: '硕士' },
{ label: '大学', value: '大学' },
{ label: '大专', value: '大专' },
{ label: '高中、高职、中专', value: '高中、高职、中专' },
{ label: '初中', value: '初中' },
{ label: '小学', value: '小学' }
]
}
},
onLoad(){
//console.log(this.utils.apiUrlReturn());
},
methods: {
//
showDatePicker() {
this.datePickerShow = true
},
//
onDateConfirm(e) {
this.form.userymd = e.year + '/' + e.month + '/' + e.day;
this.datePickerShow = false
},
//
chooseImage() {
console.log(123);
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0]
//
this.form.imageFile = tempFilePath
// URL
this.form.oneimage = tempFilePath
uni.showToast({
title: '图片选择成功',
icon: 'success'
})
},
fail: (res) => {
console.log(res);
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
//
previewImage() {
if (this.form.oneimage) {
uni.previewImage({
urls: [this.form.oneimage],
current: this.form.oneimage
})
}
},
//
submitForm() {
//
if (!this.agreementChecked.includes('agree')) {
uni.showToast({
title: '请先同意用户服务协议和隐私政策',
icon: 'none'
})
return
}
//
if (!this.validateForm()) {
return
}
this.submitting = true
//
const formData = {
name: this.form.name,
sex: this.form.sex,
code: this.form.code,
userymd: this.form.userymd,
phone: this.form.phone,
kemu: this.form.kemu.join(','), //
jibie: this.form.jibie,
type: this.form.type.join(','), //
by_school: this.form.by_school,
by_zy: this.form.by_zy,
zgxl: this.form.zgxl,
danwei: this.form.danwei,
leijishijian: this.form.leijishijian,
pxjd: this.form.pxjd
}
// 使uni.uploadFile
uni.uploadFile({
url: this.utils.apiUrlReturn() + '/addons/exam/gzinfo/add', //
filePath: this.form.imageFile,
name: 'oneimage', //
formData: formData, //
header: {
'token': uni.getStorageSync('token')
},
success: (res) => {
this.submitting = false;
console.log(res);
const data = JSON.parse(res.data)
if(data.code===401){
uni.showToast({
title: '请登录后提交!',
icon: 'none'
})
this.$refs.login.modal = true;
return;
}
if (res.statusCode === 200 && data.code === 1) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
//
this.resetForm()
} else {
uni.showToast({
title: data.message || '提交失败',
icon: 'none'
})
}
},
fail: (error) => {
this.submitting = false
uni.showToast({
title: '提交失败',
icon: 'none'
})
console.error('提交错误:', error)
}
})
},
//
validateForm() {
//
if (!this.form.name || this.form.name.trim() === '') {
uni.showToast({
title: '请输入姓名',
icon: 'none'
})
return false
}
//
if (!this.form.sex || this.form.sex === '') {
uni.showToast({
title: '请选择性别',
icon: 'none'
})
return false
}
//
if (!this.form.code || this.form.code.trim() === '') {
uni.showToast({
title: '请输入身份证号',
icon: 'none'
})
return false
}
//
const idCardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
if (!idCardReg.test(this.form.code)) {
uni.showToast({
title: '身份证号格式不正确',
icon: 'none'
})
return false
}
//
if (!this.form.userymd || this.form.userymd === '') {
uni.showToast({
title: '请选择出生日期',
icon: 'none'
})
return false
}
//
if (!this.form.phone || this.form.phone.trim() === '') {
uni.showToast({
title: '请输入联系电话',
icon: 'none'
})
return false
}
//
const phone = this.form.phone.trim()
// 11
if (!/^\d{11}$/.test(phone)) {
uni.showToast({
title: '手机号必须为11位数字',
icon: 'none'
})
return false
}
// 1
if (!phone.startsWith('1')) {
uni.showToast({
title: '手机号必须以1开头',
icon: 'none'
})
return false
}
// 3-9
const secondDigit = phone.charAt(1)
if (!/[3-9]/.test(secondDigit)) {
uni.showToast({
title: '手机号第二位必须为3-9',
icon: 'none'
})
return false
}
//
const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (!phoneReg.test(phone)) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
})
return false
}
//
if (!this.form.imageFile) {
uni.showToast({
title: '请选择蓝底电子版照片',
icon: 'none'
})
return false
}
//
if (!this.form.kemu || this.form.kemu.length === 0) {
uni.showToast({
title: '请选择报考科目',
icon: 'none'
})
return false
}
//
if (!this.form.jibie || this.form.jibie === '') {
uni.showToast({
title: '请选择报考级别',
icon: 'none'
})
return false
}
//
if (!this.form.type || this.form.type.length === 0) {
uni.showToast({
title: '请选择报考类型',
icon: 'none'
})
return false
}
//
if (!this.form.by_school || this.form.by_school.trim() === '') {
uni.showToast({
title: '请输入毕业学校',
icon: 'none'
})
return false
}
//
if (!this.form.by_zy || this.form.by_zy.trim() === '') {
uni.showToast({
title: '请输入毕业专业',
icon: 'none'
})
return false
}
//
if (!this.form.zgxl || this.form.zgxl === '') {
uni.showToast({
title: '请选择最高学历',
icon: 'none'
})
return false
}
//
if (!this.form.danwei || this.form.danwei.trim() === '') {
uni.showToast({
title: '请输入工作单位',
icon: 'none'
})
return false
}
//
if (!this.form.leijishijian || this.form.leijishijian.trim() === '') {
uni.showToast({
title: '请输入累计从事本职业时间',
icon: 'none'
})
return false
}
//
if (!this.form.pxjd || this.form.pxjd.trim() === '') {
uni.showToast({
title: '请输入培训基地',
icon: 'none'
})
return false
}
//
return true
},
//
openUserAgreement() {
//
uni.showToast({
title: '打开用户服务协议',
icon: 'none'
})
},
//
openPrivacyPolicy() {
//
uni.showToast({
title: '打开隐私政策',
icon: 'none'
})
},
//
toggleSubject(value) {
const index = this.form.kemu.indexOf(value)
if (index > -1) {
//
this.form.kemu.splice(index, 1)
} else {
//
this.form.kemu.push(value)
}
},
//
toggleExamType(value) {
const index = this.form.type.indexOf(value)
if (index > -1) {
//
this.form.type.splice(index, 1)
} else {
//
this.form.type.push(value)
}
},
//
validatePhone() {
const phone = this.form.phone.trim()
//
if (!phone) {
return
}
//
if (phone.length !== 11) {
uni.showToast({
title: '手机号必须为11位',
icon: 'none',
duration: 1500
})
return
}
//
const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (!phoneReg.test(phone)) {
uni.showToast({
title: '请输入正确的手机号码',
icon: 'none',
duration: 1500
})
}
},
//
resetForm() {
//
this.form = {
name: '', //
sex: '', //
code: '', //
userymd: '', //
phone: '', //
oneimage: '', // URL
imageFile: null, //
kemu: [], //
jibie: '', //
type: [], //
by_school: '', //
by_zy: '', //
zgxl: '', //
danwei: '', //
leijishijian: '', //
pxjd: '' //
}
//
this.agreementChecked = []
//
this.datePickerShow = false
uni.showToast({
title: '表单已重置',
icon: 'success',
duration: 1500
})
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
background-color: #f8f8f8;
padding: 20rpx;
}
.form-container {
background-color: #ffffff;
border-radius: 20rpx;
padding: 0rpx 40rpx;
padding-bottom: 50rpx;
}
//
.form-item-vertical {
/deep/ .tn-form-item__body {
flex-direction: column;
align-items: flex-start;
}
/deep/ .tn-form-item__label {
margin-bottom: 20rpx;
font-weight: bold;
color: #333;
position: relative;
}
// *
/deep/ .tn-form-item--left__content--required {
position: absolute;
left: -20rpx;
top: 50%;
transform: translateY(-50%);
color: #ff0000 !important;
order: -1;
}
/deep/ .tn-form-item--left__content {
position: relative;
}
/deep/ .tn-form-item__content {
width: 100%;
}
// 线
/deep/ .tn-form-item {
border-bottom: none !important;
}
/deep/ .tn-form-item::after {
display: none !important;
}
// 100%
/deep/ .tn-input {
width: 640rpx;
background-color: #F7F7F7 !important;
border: none !important;
padding: 20rpx;
height: 100rpx;
}
/deep/ .tn-input__input {
width: 100%;
background-color: #F7F7F7 !important;
border: none !important;
padding: 20rpx;
height: 100rpx;
}
/deep/ .tn-input__wrap {
background-color: #F7F7F7 !important;
border: none !important;
}
}
//
.date-picker-wrapper {
position: relative;
width: 640rpx;
/deep/ .tn-input {
width: 640rpx;
background-color: #F7F7F7 !important;
border: none !important;
}
/deep/ .tn-input__input {
width: 100%;
background-color: #F7F7F7 !important;
border: none !important;
}
/deep/ .tn-input__wrap {
background-color: #F7F7F7 !important;
border: none !important;
}
.picker-icon {
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
color: #999;
font-size: 32rpx;
}
}
//
.upload-new-wrapper {
width: 640rpx;
.upload-status {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 10rpx 20rpx 30rpx;
background-color: #F7F7F7;
border-radius: 0rpx;
height: 100rpx;
box-sizing: border-box;
.upload-status-text {
color: #666;
font-size: 28rpx;
flex: 1;
display: flex;
align-items: center;
.preview-link {
color: #1A73E8;
text-decoration: underline;
cursor: pointer;
}
}
.upload-btn {
padding: 8rpx 20rpx;
.upload-btn-text {
color: #333;
font-size: 24rpx;
}
}
}
.preview-section {
margin-top: 20rpx;
.preview-thumb {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
border: 1rpx solid #eee;
}
}
}
//
.subject-tags {
display: flex;
flex-direction: column;
gap: 20rpx;
.subject-tag {
position: relative;
width: 640rpx;
padding: 10rpx 40rpx;
border-radius: 0rpx;
background-color: #f8f8f8;
color: #666;
font-size: 28rpx;
transition: all 0.3s ease;
text-align: left;
display: flex;
align-items: center;
justify-content: space-between;
&--selected {
border-color: #1A73E8;
background-color: #e8f0fe;
color: #1A73E8;
}
&__check {
width: 40rpx;
height: 40rpx;
background-color: #1A73E8;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24rpx;
flex-shrink: 0;
}
}
}
//
.exam-type-tags {
display: flex;
flex-direction: column;
gap: 20rpx;
.exam-type-tag {
position: relative;
width: 640rpx;
padding: 10rpx 40rpx;
background-color: #f8f8f8;
color: #666;
font-size: 28rpx;
transition: all 0.3s ease;
text-align: left;
display: flex;
align-items: center;
justify-content: space-between;
&--selected {
background-color: #e8f0fe;
color: #1A73E8;
}
&__check {
width: 40rpx;
height: 40rpx;
background-color: #1A73E8;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24rpx;
flex-shrink: 0;
}
}
}
//
.agreement-section {
margin-top: 30rpx;
display: flex;
align-items: center;
}
.agreement-text {
color: #666;
font-size: 26rpx;
}
.agreement-link {
color: #1A73E8;
font-size: 26rpx;
}
//
.submit-section {
margin-top: 30rpx;
padding: 0 20rpx;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
static/img/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -201,6 +201,7 @@
overflow: hidden;
user-select: none;
line-height: 1.8;
padding-bottom: 20rpx;
&__icon-wrap {
color: $tn-font-color;
@ -216,7 +217,7 @@
text-align: center;
transition-property: color, border-color, background-color;
font-size: 20rpx;
border: 1rpx solid $tn-font-sub-color;
border: 1px solid $tn-font-sub-color;
transition-duration: 0.2s;
/* #ifdef MP-TOUTIAO */