Browse Source

feat: h5;

h5
Fox-33 1 week ago
parent
commit
7d2d0022a2
61 changed files with 197 additions and 4448 deletions
  1. +31
    -0
      index.html
  2. +7
    -2
      manifest.json
  3. +2
    -1
      package.json
  4. +4
    -60
      pages.json
  5. +0
    -229
      pages/index/center.vue
  6. +0
    -153
      pages/index/index.vue
  7. +0
    -113
      pages/index/report.vue
  8. +104
    -9
      pages/report/index.vue
  9. +48
    -15
      pages/report/progressCircle.vue
  10. +0
    -0
      pages/report/reportTableView.vue
  11. +0
    -115
      pages_order/auth/agreementConfirmPopup.vue
  12. +0
    -276
      pages_order/auth/infoModify.vue
  13. +0
    -347
      pages_order/auth/loginAndRegisterAndForgetPassword.vue
  14. +0
    -161
      pages_order/auth/wxLogin.vue
  15. +0
    -285
      pages_order/auth/wxUserInfo.vue
  16. +0
    -101
      pages_order/components/agreementModal.vue
  17. +0
    -47
      pages_order/components/formTextarea.vue
  18. +0
    -102
      pages_order/components/formUpload.vue
  19. +0
    -301
      pages_order/feedback/index copy.vue
  20. +0
    -262
      pages_order/feedback/index.vue
  21. +0
    -85
      pages_order/report/codeErrorPopup.vue
  22. +0
    -299
      pages_order/report/pay.vue
  23. +0
    -262
      pages_order/report/userInfo.vue
  24. +0
    -55
      pages_order/service/commonQuestion.vue
  25. +0
    -198
      pages_order/service/index.vue
  26. +0
    -119
      pages_order/service/popupPhone.vue
  27. +0
    -86
      pages_order/service/popupQrCode.vue
  28. BIN
      pages_order/static/auth/avatar-default.png
  29. BIN
      pages_order/static/feedback/icon-camera.png
  30. BIN
      pages_order/static/feedback/icon-star.png
  31. BIN
      pages_order/static/report/icon-coupon.png
  32. BIN
      pages_order/static/report/icon-info.png
  33. BIN
      pages_order/static/report/icon-wx.png
  34. BIN
      pages_order/static/service/bg-popup-phone.png
  35. BIN
      pages_order/static/service/bg-popup-qr.png
  36. BIN
      pages_order/static/service/icon-message.png
  37. BIN
      pages_order/static/service/icon-phone.png
  38. BIN
      pages_order/static/service/icon-service.png
  39. BIN
      pages_order/static/service/icon-wx.png
  40. BIN
      pages_order/static/test/bg-test-finsih.png
  41. BIN
      pages_order/static/test/icon-warning.png
  42. +0
    -428
      pages_order/test/answer.vue
  43. +0
    -51
      pages_order/test/list.vue
  44. +0
    -162
      pages_order/test/start.vue
  45. +0
    -124
      pages_order/test/testCard.vue
  46. BIN
      static/image/avatar-default.png
  47. BIN
      static/image/icon-center-feedback.png
  48. BIN
      static/image/icon-center-logout.png
  49. BIN
      static/image/icon-center-service.png
  50. BIN
      static/image/icon-center-test.png
  51. BIN
      static/image/icon-center-userinfo.png
  52. BIN
      static/image/icon-index.png
  53. BIN
      static/image/icon-unfinish.png
  54. BIN
      static/image/icon.png
  55. BIN
      static/image/tabbar/home-active.png
  56. BIN
      static/image/tabbar/home.png
  57. BIN
      static/image/tabbar/report-active.png
  58. BIN
      static/image/tabbar/report.png
  59. BIN
      static/image/tabbar/user-center-active.png
  60. BIN
      static/image/tabbar/user-center.png
  61. +1
    -0
      uni.webview.1.5.6.js

+ 31
- 0
index.html View File

@ -16,5 +16,36 @@
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
<script type="text/javascript">
var userAgent = navigator.userAgent;
if (userAgent.indexOf('AlipayClient') > -1) {
// 支付宝小程序的 JS-SDK 防止 404 需要动态加载,如果不需要兼容支付宝小程序,则无需引用此 JS 文件。
document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');
} else if (/QQ/i.test(userAgent) && /miniProgram/i.test(userAgent)) {
// QQ 小程序
document.write(
'<script type="text/javascript" src="https://qqq.gtimg.cn/miniprogram/webview_jssdk/qqjssdk-1.0.0.js"><\/script>'
);
} else if (/miniProgram/i.test(userAgent) && /micromessenger/i.test(userAgent)) {
// 微信小程序 JS-SDK 如果不需要兼容微信小程序,则无需引用此 JS 文件。
document.write('<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"><\/script>');
} else if (/toutiaomicroapp/i.test(userAgent)) {
// 头条小程序 JS-SDK 如果不需要兼容头条小程序,则无需引用此 JS 文件。
document.write(
'<script type="text/javascript" src="https://lf1-cdn-tos.bytegoofy.com/goofy/developer/jssdk/jssdk-1.2.0.js"><\/script>');
} else if (/swan/i.test(userAgent)) {
// 百度小程序 JS-SDK 如果不需要兼容百度小程序,则无需引用此 JS 文件。
document.write(
'<script type="text/javascript" src="https://b.bdstatic.com/searchbox/icms/searchbox/js/swan-2.0.18.js"><\/script>'
);
} else if (/quickapp/i.test(userAgent)) {
// quickapp
document.write('<script type="text/javascript" src="https://quickapp/jssdk.webview.min.js"><\/script>');
}
</script>
<!-- uni 的 SDK -->
<!-- 需要把 uni.webview.1.5.6.js 下载到自己的服务器 -->
<!-- <script src="https://gitcode.net/dcloud/uni-app/-/raw/dev/dist/uni.webview.1.5.6.js"></script> -->
<script src="./uni.webview.1.5.6.js"></script>
</body>
</html>

+ 7
- 2
manifest.json View File

@ -1,6 +1,6 @@
{
"name" : "unapp模板",
"appid" : "__UNI__197A38F",
"appid" : "__UNI__40D2531",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
@ -89,7 +89,7 @@
}
},
"devServer" : {
"https" : false,
"https" : true,
"proxy" : {
"/ws/geocoder/v1/" : {
"target" : "https://apis.map.qq.com",
@ -100,6 +100,11 @@
"changeOrigin" : true
}
}
},
"optimization" : {
"treeShaking" : {
"enable" : true
}
}
}
}

+ 2
- 1
package.json View File

@ -15,6 +15,7 @@
"license": "ISC",
"dependencies": {
"ali-oss": "^6.21.0",
"dayjs": "^1.11.12"
"dayjs": "^1.11.12",
"html2canvas": "^1.4.1"
}
}

+ 4
- 60
pages.json View File

@ -1,22 +1,10 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/index/report",
"path": "pages/report/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": true
}
},
{
"path": "pages/index/center",
"style": {
"navigationBarTitleText": ""
"navigationStyle": "custom"
}
}
],
@ -26,54 +14,10 @@
"packages": ["pages_order"]
}
},
"subPackages": [{
"root": "pages_order",
"pages": [
{
"path": "auth/wxLogin"
},
{
"path": "auth/wxUserInfo"
},
{
"path": "auth/infoModify"
},
{
"path": "auth/loginAndRegisterAndForgetPassword"
},
{
"path": "test/start"
},
{
"path": "test/answer"
},
{
"path": "test/list"
},
{
"path": "report/pay"
},
{
"path": "report/userInfo"
},
{
"path": "report/index"
},
{
"path": "service/index"
},
{
"path": "service/commonQuestion"
},
{
"path": "feedback/index"
}
]
}],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "测试",
"navigationBarBackgroundColor": "#F8F8F8",
"navigationBarTitleText": "报告",
"navigationBarBackgroundColor": "#014FA2",
"backgroundColor": "#F8F8F8",
"navigationStyle": "custom"
},


+ 0
- 229
pages/index/center.vue View File

@ -1,229 +0,0 @@
<template>
<view class="page__view">
<view class="bg"></view>
<view class="main">
<view class="flex user">
<!-- 用户信息 -->
<template v-if="isLogin">
<view class="user-avatar">
<image class="user-avatar-img" :src="userInfo.headImage" mode="scaleToFill"></image>
</view>
<view class="user-info">
<view class="user-info-name">{{ userInfo.nickName }}</view>
<view class="user-info-desc">{{ `ID:${userInfo.id}` }}</view>
</view>
</template>
<template v-else>
<view class="user-avatar">
<image class="user-avatar-img" src="@/static/image/avatar-default.png" mode="scaleToFill"></image>
</view>
<view class="user-info">
<view class="user-info-tips">暂未登录 请先登录</view>
</view>
</template>
</view>
<!-- 用户菜单 -->
<template v-if="isLogin">
<view class="card">
<view class="card-header">常用功能</view>
<view class="card-content menu">
<view class="flex flex-column menu-item" v-for="item in list" :key="item.id" @click="onClick(item)">
<image class="icon" :src="item.icon" mode="widthFix"></image>
<view>{{ item.label }}</view>
</view>
</view>
</view>
</template>
<!-- 用户登陆 -->
<template v-else>
<view class="login">
<button class="btn" @click="$utils.toLogin">立即登录</button>
<view class="tips">暂未登录 请先登录</view>
</view>
</template>
</view>
<tabber select="center" />
</view>
</template>
<script>
import { mapState } from 'vuex'
import tabber from '@/components/base/tabbar.vue'
export default {
components: {
tabber,
},
data() {
return {
list: [
{ id: '001', label: '我的答题', icon: '/static/image/icon-center-test.png', path: '/pages_order/test/list' },
{ id: '002', label: '咨询客服', icon: '/static/image/icon-center-service.png', path: '/pages_order/service/index' },
{ id: '003', label: '意见反馈', icon: '/static/image/icon-center-feedback.png', path: '/pages_order/feedback/index' },
{ id: '004', label: '个人信息', icon: '/static/image/icon-center-userinfo.png', path: '/pages_order/auth/infoModify' },
{ id: '008', label: '退出登录', icon: '/static/image/icon-center-logout.png', key: 'logout' },
],
}
},
computed: {
...mapState(['userInfo', 'configList']),
isLogin() {
return this.userInfo && this.userInfo.id
}
},
onShow() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
methods: {
onClick(target) {
const { key, path } = target
switch(key) {
case 'logout':
this.$store.commit('logout')
break
default:
path && this.$utils.navigateTo(path)
break
}
},
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
}
.bg {
width: 100%;
height: 501rpx;
background: linear-gradient(160deg, #014FA2 36%, #4C8FD6);
}
.main {
width: 100%;
position: absolute;
top: 0;
left: 0;
padding: 216rpx 13rpx 26rpx 13rpx;
box-sizing: border-box;
}
.user {
padding: 0 33rpx;
column-gap: 22rpx;
&-avatar {
flex: none;
width: 118rpx;
height: 118rpx;
border-radius: 50%;
overflow: hidden;
&-img {
width: 100%;
height: 100%;
}
}
&-info {
flex: 1;
color: #FFFFFF;
&-name {
font-size: 30rpx;
}
&-desc {
margin-top: 12rpx;
font-size: 28rpx;
}
&-tips {
font-size: 30rpx;
}
}
}
.card {
margin-top: 83rpx;
width: 100%;
min-height: 652rpx;
padding: 32rpx 30rpx;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 16rpx;
&-header {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
&-content {
margin-top: 73rpx;
}
}
.menu {
width: 100%;
display: grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 73rpx;
row-gap: 93rpx;
&-item {
min-width: 0;
row-gap: 10rpx;
font-size: 28rpx;
white-space: nowrap;
color: #000000;
.icon {
width: 50rpx;
height: auto;
}
}
}
.login {
margin-top: 307rpx;
width: 100%;
padding: 0 128rpx;
box-sizing: border-box;
.btn {
padding: 16rpx 0;
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1.4;
color: #FFFFFF;
background: #014FA2;
border-radius: 41rpx;
}
.tips {
margin-top: 16rpx;
text-align: center;
font-family: PingFang SC;
font-weight: 400;
font-size: 26rpx;
line-height: 1.4;
color: #A3A3A3;
}
}
</style>

+ 0
- 153
pages/index/index.vue View File

@ -1,153 +0,0 @@
<template>
<view class="page__view">
<view class="bg"></view>
<view class="main">
<view class="swiper">
<uv-swiper
:list="bannerList" keyName="image"
indicator
indicatorMode="dot"
indicatorActiveColor="#62BBFF"
indicatorInactiveColor="#FFFFFF"
height="340rpx"
></uv-swiper>
</view>
<view class="flex flex-column card">
<view class="title">公司风险检测</view>
<image class="icon" src="@/static/image/icon-index.png" mode="widthFix"></image>
<button class="btn" @click="onStartTest">开始测评</button>
</view>
<unfinishTestPopup ref="unfinishTestPopup"></unfinishTestPopup>
<tabber select="home" />
</view>
</view>
</template>
<script>
import tabber from '@/components/base/tabbar.vue'
import unfinishTestPopup from '@/components/home/unfinishTestPopup.vue'
export default {
components: {
tabber,
unfinishTestPopup,
},
data() {
return {
bannerList: [],
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
this.fetchBanner()
},
onShow() {
if(uni.getStorageSync('token')){
this.fetchUnfinish()
}
},
methods: {
async fetchBanner() {
try {
this.bannerList = (await this.$fetch('queryBannerList', { type: '0' }))?.records // type0-
} catch (err) {
}
},
async fetchUnfinish() {
// todo: delete
// let data = { id: '001', unfinishCount: 15, current: 18, }
// this.$refs.unfinishTestPopup.open(data)
try {
const { records, total } = await this.$fetch('queryExamLogList', { pageNo: 1, pageSize: 1, isFinished: '0' })
total && this.$refs.unfinishTestPopup.open(records[0])
} catch (err) {
}
},
onStartTest() {
uni.navigateTo({
url: `/pages_order/test/start`
})
},
},
}
</script>
<style scoped lang="scss">
.bg {
width: 100%;
height: 376rpx;
background: linear-gradient(164deg, #014FA2 30%, #4C8FD6);
}
.main {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 174rpx 30rpx 0 30rpx;
box-sizing: border-box;
}
.swiper {
border-radius: 10rpx;
overflow: hidden;
/deep/ .uv-swiper-indicator__wrapper__dot,
/deep/ .uv-swiper-indicator__wrapper__dot--active {
width: 5px;
}
}
.card {
margin-top: 32rpx;
justify-content: space-between;
min-height: 803rpx;
padding: 135rpx 0 55rpx 0;
box-sizing: border-box;
background: linear-gradient(rgba($color: #FCFDFE, $alpha: 0.93), rgba($color: #FCFDFE, $alpha: 0.93) 180rpx, rgba($color: #3381D4, $alpha: 0.43));
border-radius: 25rpx;
border: 3rpx solid #FFFFFF;
box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
.title {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
.icon {
margin: 99rpx 0 86rpx;
width: 285rpx;
height: auto;
}
.btn {
padding: 20rpx 212rpx;
font-size: 30rpx;
white-space: nowrap;
color: #FFFFFF;
line-height: 1.4;
background: #014FA2;
border-radius: 42rpx;
}
}
</style>

+ 0
- 113
pages/index/report.vue View File

@ -1,113 +0,0 @@
<template>
<view class="page__view">
<view class="header"></view>
<template v-if="isLogin">
<view class="list">
<view class="list-item" v-for="item in list" :key="item.id">
<reportCard :data="item"></reportCard>
</view>
</view>
</template>
<!-- 用户登陆 -->
<template v-else>
<view class="login">
<button class="btn" @click="$utils.toLogin">立即登录</button>
<view class="tips">暂未登录 请先登录</view>
</view>
</template>
<tabber select="report" />
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import tabber from '@/components/base/tabbar.vue'
import reportCard from '@/components/report/reportCard.vue'
export default {
mixins: [mixinsList],
components: {
tabber,
reportCard,
},
data() {
return {
mixinsListApi: '',
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
computed: {
isLogin() {
return this.userInfo && this.userInfo.id
},
},
onShow() {
this.mixinsListApi = uni.getStorageSync('token') ? 'queryReportList' : ''
this.getData()
},
methods: {
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
}
.header {
width: 100%;
height: calc(var(--status-bar-height) + 120rpx);
background: linear-gradient(164deg, #014FA2, #4C8FD6);
}
.list {
width: 100%;
padding: 29rpx;
box-sizing: border-box;
background: #F5F5F5;
&-item {
& + & {
margin-top: 23rpx;
}
}
}
.login {
margin-top: 307rpx;
width: 100%;
padding: 0 128rpx;
box-sizing: border-box;
.btn {
padding: 16rpx 0;
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1.4;
color: #FFFFFF;
background: #014FA2;
border-radius: 41rpx;
}
.tips {
margin-top: 16rpx;
text-align: center;
font-family: PingFang SC;
font-weight: 400;
font-size: 26rpx;
line-height: 1.4;
color: #A3A3A3;
}
}
</style>

pages_order/report/index.vue → pages/report/index.vue View File

@ -1,8 +1,15 @@
<template>
<view class="page__view">
<navbar title="报告" leftClick @leftClick="$utils.navigateBack" />
<view ref="report" class="page__view export">
<!-- <navbar title="报告" leftClick @leftClick="$utils.navigateBack" /> -->
<template v-if="detail">
<template v-if="tempFilePath">
<img
:src="tempFilePath"
@contextmenu.prevent
style="display: block; width: 100vw; height: auto;"
/>
</template>
<template v-else-if="detail">
<view class="title">{{ detail.title }}</view>
<view class="section">
@ -36,21 +43,28 @@
<view class="flex flex-column contact">
<view>扫下方二维码联系我们给你1V1解决方案</view>
<image class="qr" :src="configList.company_qrcode" :show-menu-by-longpress="true" mode="widthFix"></image>
<img class="qr" style="display: block;" :src="configList.company_qrcode" crossorigin=anonymous />
</view>
<view>
<image class="img" :src="configList.company_info" mode="widthFix"></image>
<img class="img" style="display: block;" :src="configList.company_info" crossorigin=anonymous />
<view class="logo">
<image class="img" :src="configList.company_logo" mode="widthFix"></image>
<img class="img" style="display: block;" :src="configList.company_logo" crossorigin=anonymous />
</view>
</view>
</template>
<!-- <view class="bottom" data-html2canvas-ignore="true">
<button class="btn" @click="onDownload">长按图片保存到手机</button>
</view> -->
</view>
</template>
<script>
import html2canvas from 'html2canvas'
import progressCircle from './progressCircle.vue';
import reportTableView from './reportTableView.vue';
@ -63,11 +77,39 @@
return {
detail: null,
tableList: [],
canvas: null,
tempFilePath: null
}
},
onLoad(arg) {
const { batchNo } = arg
this.getData(batchNo)
async onLoad(arg) {
uni.showLoading({
title: '生成中...'
})
document.addEventListener('UniAppJSBridgeReady', function() {
console.log('UniAppJSBridgeReady', uni)
uni.getEnv(function(res) {
console.log('当前环境:' + JSON.stringify(res));
});
})
const { batchNo, token } = arg
token && uni.setStorageSync('token', token)
await this.getData(batchNo)
setTimeout(async () => {
await this.createImage()
uni.hideLoading()
// H5
uni.showModal({
title: '保存报告',
content: '请长按图片,选择"保存图片"即可保存到手机',
showCancel: false,
confirmText: '知道了'
})
}, 800)
},
methods: {
async getData(batchNo) {
@ -125,6 +167,37 @@
}
},
async createImage() {
console.log('createImage')
const node = document.querySelector('.export')
const canvas = await html2canvas(node, { allowTaint: true, useCORS: true, })
const image = canvas.toDataURL('image/png')
this.tempFilePath = image
uni?.postMessage?.({
data: {
imageData: image,
}
});
},
onDownload() {
if (!this.tempFilePath) {
uni.showToast({
title: '图片还未生成完成',
icon: 'none'
})
return
}
// H5
uni.showModal({
title: '保存图片',
content: '请长按上方图片,选择"保存图片"即可保存到手机',
showCancel: false,
confirmText: '知道了'
})
},
},
}
</script>
@ -218,4 +291,26 @@
padding: 42rpx 127rpx 46rpx 127rpx;
box-sizing: border-box;
}
.bottom {
position: sticky;
left: 0;
bottom: 0;
width: 100%;
padding: 35rpx 56rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 35rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 29rpx 0;
font-size: 30rpx;
line-height: 1.5;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
}
</style>

pages_order/report/progressCircle.vue → pages/report/progressCircle.vue View File

@ -1,7 +1,11 @@
<template>
<view class="flex progress_box" :style="style">
<view>{{ label || '' }}</view>
<canvas class="progress_bar" :canvas-id="`cpbar${code}`" type="2d"></canvas>
<canvas
class="progress_bar"
:canvas-id="`cpbar${code}`"
:id="`cpbar${code}`"
type="2d"></canvas>
<view class="value">{{ value || 0 }}</view>
</view>
</template>
@ -41,6 +45,27 @@
},
methods: {
drawProgress(color) {
const ctx = uni.createCanvasContext(`cpbar${this.code}`)
let Ratio = 1 / 2
let w = 14 * Ratio
ctx.setLineWidth(w); //
ctx.setStrokeStyle(color); //
let width = 126 * Ratio
let height = 126 * Ratio
ctx.beginPath();
let x = width / 2
let y = height / 2
let r = 62 * Ratio - w / 2
ctx.arc(x, y, r, START, END, false);
ctx.stroke();
ctx.draw()
return
uni.createSelectorQuery().in(this)
.select('.progress_bar')
.fields({
@ -48,26 +73,32 @@
size: true
})
.exec(async (res) => {
const canvas = res[0].node
// const canvas = res[0].node
console.log('res', res)
// Canvas
const width = res[0].width
const height = res[0].height
//dpr
const dpr = wx.getWindowInfo().pixelRatio
canvas.width = width * dpr
canvas.height = height * dpr
let Ratio = width / 126
// const width = res[0].width
// const height = res[0].height
const width = res.width
const height = res.height
// //dpr
// const dpr = wx.getWindowInfo().pixelRatio
// canvas.width = width * dpr
// canvas.height = height * dpr
// let Ratio = width / 126
let Ratio = 1
console.log('Ratio', Ratio)
//
const ctx = canvas.getContext('2d')
const ctx = uni.createCanvasContext('myCanvas', this)
console.log('ctx', ctx)
ctx.scale(dpr, dpr)
ctx.clearRect(0, 0, width, height)
// ctx.scale(dpr, dpr)
// ctx.clearRect(0, 0, width, height)
let w = 14 * Ratio
ctx.lineWidth = w; //
ctx.strokeStyle = color; //
ctx.setLineWidth(w); //
ctx.setStrokeStyle(color); //
// ctx.lineCap = 'round'; //
ctx.beginPath();
@ -76,6 +107,8 @@
let r = 62 * Ratio - w / 2
ctx.arc(x, y, r, START, END, false);
ctx.stroke();
ctx.draw()
})
},

pages_order/report/reportTableView.vue → pages/report/reportTableView.vue View File


+ 0
- 115
pages_order/auth/agreementConfirmPopup.vue View File

@ -1,115 +0,0 @@
<template>
<view>
<uv-popup ref="popup" :round="24">
<view class="popup__view">
<view class="header">
用户隐私保护提示
</view>
<view class="content">
在你使用 {{ configList.app_name }}服务之前请仔细阅读我已阅读并同意
<text class="highlight" @click="$refs.modal.open('config_privacy', '服务协议与隐私条款')">服务协议与隐私条款</text>
<text class="highlight" @click="$refs.modal.open('config_agreement', '个人信息保护指引')">个人信息保护指引</text>
如你同意该指引请点击同意开始使用本小程序
</view>
<view class="footer">
<button class="btn" @click="onConfirm(false)">拒绝</button>
<button class="btn btn-confirm" @click="onConfirm(true)">同意</button>
</view>
</view>
</uv-popup>
<agreementModal ref="modal" @confirm="onConfirmSingle"></agreementModal>
</view>
</template>
<script>
import agreementModal from '@/pages_order/components/agreementModal.vue'
export default {
name: 'agreementModal',
components: {
agreementModal,
},
data() {
return {
confirmSet: new Set(),
}
},
methods: {
open() {
this.$refs.popup.open('bottom');
},
onConfirm(confirm) {
this.$emit('confirm', confirm)
this.$refs.popup.close();
},
onConfirmSingle(confirm, key) {
if (!this.confirmSet.has(key) && confirm) {
this.confirmSet.add(key)
} else if (this.confirmSet.has(key) && !confirm) {
this.confirmSet.delete(key)
}
if (this.confirmSet.size === 2) {
this.onConfirm(true)
}
}
},
}
</script>
<style lang="scss" scoped>
.popup__view {
display: flex;
flex-direction: column;
padding: 44rpx 46rpx 128rpx 46rpx;
}
.header {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 600;
line-height: 1.5;
color: #000000;
}
.content {
margin-top: 30rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.5;
text-align: left;
color: #000000;
.highlight {
color: #4C6EAE;
}
}
.footer {
margin-top: 122rpx;
text-align: center;
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8rpx;
width: 232rpx;
padding: 18rpx 84rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
background: #F5F5F5;
color: #07C160;
&-confirm {
background: #07C160;
color: #FFFFFF;
}
}
.btn + .btn {
margin-left: 30rpx;
}
}
</style>

+ 0
- 276
pages_order/auth/infoModify.vue View File

@ -1,276 +0,0 @@
<template>
<view class="page__view">
<navbar title="资料修改" leftClick @leftClick="$utils.navigateBack" />
<view class="form">
<view class="flex form-header">
<view class="line"></view>
<view>个人信息</view>
</view>
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="headImage" :customStyle="formItemStyle">
<button class="btn btn-avatar" :plain="true" :hairline="false" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<view class="flex flex-column avatar-box">
<view v-if="form.headImage" class="avatar">
<image class="img" :src="form.headImage" mode="aspectFill"></image>
</view>
<view v-else class="flex avatar">
<image class="img" src="@/static/image/avatar-default.png" mode="scaleToFill"></image>
</view>
<view>点击更换头像</view>
</view>
</button>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="nickName" :customStyle="formItemStyle">
<view class="flex row">
<view class="row-label">昵称</view>
<view class="row-content input">
<input
v-model="form.nickName"
type="nickname"
placeholder="请输入"
placeholderStyle="color: #999999; font-size: 30rpx; font-weight: 400;"
style="text-align: right;"
/>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="phone" :customStyle="formItemStyle">
<view class="flex row">
<view class="row-label">手机号</view>
<view class="row-content input">
<input
v-model="form.phone"
placeholder="请输入"
placeholderStyle="color: #999999; font-size: 30rpx; font-weight: 400;"
style="text-align: right;"
:disabled="!!userInfo.phone"
/>
</view>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
<view class="bottom">
<button class="btn" @click="onSubmit">保存</button>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
props: {
mode: {
type: String,
default: null,
}
},
data() {
return {
form: {
nickName: null,
phone: null,
headImage: null,
},
rules: {
'nickName': {
type: 'string',
required: true,
message: '请输入昵称',
},
'phone': {
type: 'string',
required: true,
message: '请输入手机号',
},
'headImage': {
type: 'string',
required: false,
message: '请选择头像',
},
},
formItemStyle: { padding: 0 },
}
},
computed: {
...mapState(['userInfo']),
},
onLoad(arg) {
this.mode = arg.mode
this.form.nickName = this.userInfo.nickName || ''
this.form.phone = this.userInfo.phone || ''
this.form.headImage = this.userInfo.headImage || ''
},
methods: {
onChooseAvatar(res) {
this.$Oss.ossUpload(res.target.avatarUrl)
.then(url => {
this.form.headImage = url
})
},
getPhone(e){
this.$api('bindPhone', {
code : e.detail.code
}, res => {
if(res.code == 200){
if(res.success){
this.form.phone = res.result
}else{
uni.showModal({
title: res.message
})
}
}
})
},
async onSubmit() {
try {
await this.$refs.form.validate()
const {
nickName,
phone,
headImage,
} = this.form
const params = {
nickName,
phone,
headImage,
}
await this.$fetch('updateInfo', params, false)
uni.showToast({
icon: 'success',
title: '保存成功',
});
this.$store.commit('getUserInfo')
setTimeout(uni.navigateBack, 1000, -1)
} catch (err) {
console.log('onSubmit err', err)
}
},
},
}
</script>
<style lang="scss" scoped>
.form {
padding: 34rpx 22rpx;
&-header {
justify-content: flex-start;
padding: 0 18rpx;
column-gap: 7rpx;
font-family: PingFang SC;
font-weight: 600;
font-size: 36rpx;
line-height: 1.4;
color: #000000;
margin-bottom: 24rpx;
.line {
width: 9rpx;
height: 33rpx;
background: #014FA2;
border-radius: 5rpx;
}
}
&-item {
& + & {
margin-top: 34rpx;
border-bottom: 0.5rpx solid rgba($color: #707070, $alpha: 0.14);
}
}
}
.btn-avatar {
margin-bottom: 27rpx;
display: inline-block;
width: auto;
border: none;
}
.avatar-box {
box-sizing: border-box;
row-gap: 9rpx;
font-size: 28rpx;
color: rgba($color: #999999, $alpha: 0.5);
}
.avatar {
position: relative;
width: 157rpx;
height: 157rpx;
border-radius: 50%;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
}
.row {
padding: 12rpx 69rpx 12rpx 23rpx;
justify-content: space-between;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.4;
font-size: 30rpx;
color: #8B8B8B;
& + & {
margin-top: 32rpx;
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
padding: 0 78rpx 231rpx 78rpx;
box-sizing: border-box;
.btn {
width: 100%;
padding: 25rpx 0;
box-sizing: border-box;
font-size: 32rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 41rpx;
}
}
</style>

+ 0
- 347
pages_order/auth/loginAndRegisterAndForgetPassword.vue View File

@ -1,347 +0,0 @@
<template>
<view class="refundsOrExchange">
<navbar :title="titleList[titleIndex]" leftClick @leftClick="$utils.navigateBack" />
<view class="frame">
<!-- 登录和注册 -->
<view class="loginRegister" v-if='titleIndex!=2'>
<!-- 标题 -->
<view class="title">{{titleList[titleIndex]}}</view>
<!-- 头像 -->
<view class="userIamge">
<view>
<img src="/static/image/center/11.svg" alt="" style="width: 100%;height: 100%;">
</view>
</view>
<!-- 用户名&密码&隐私条款 -->
<view class="form">
<view>
<uv-input v-model="form.account" placeholder="请输入账号" border="surround" shape='circle'
clearable :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
<view>
<uv-input v-model="form.password" password placeholder="请输入密码" border="surround" shape='circle'
clearable :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
<view>
<uv-checkbox-group v-model="checkboxValue" shape="circle">
<view class="content">
<view style="display: flex;flex-wrap: wrap;">
<uv-checkbox size="30rpx" :name="1"></uv-checkbox>
请你阅读并同意我们的<span style="color: #fd5100"
@click="$refs.popup.open('getPrivacyPolicy')">隐私条款</span><span
style="color: #fd5100"
@click="$refs.popup.open('getUserAgreement')">服务协议</span>
</view>
</view>
</uv-checkbox-group>
</view>
</view>
</view>
<!-- 忘记密码 -->
<view class='forgetPassword' v-if='titleIndex==2'>
<!-- 标题 -->
<view class="title">{{titleList[titleIndex]}}</view>
<!-- 表单 -->
<view class="form1">
<view class="userName">
<uv-input v-model="form1.userName" placeholder="请输入手机号/用户/邮箱" border="surround" shape='circle'
clearable :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
<view class="code">
<view class="left">
<uv-input v-model="form1.code" placeholder="请输入验证码" border="surround" shape='circle'
clearable :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
<view class="right">
<view>
<uv-toast ref="toast"></uv-toast>
<uv-code :seconds="seconds" @end="end" @start="start" ref="code"
@change="codeChange"></uv-code>
<uv-button @tap="getCode" iconSize='10rpx' color='#fd5100'
shape='circle'>{{tips}}</uv-button>
</view>
</view>
</view>
<view class="password1">
<uv-input v-model="form1.password1" placeholder="设置您的新密码(6到50个字符)" password clearable
border="surround" shape='circle' :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
<view class="password2">
<uv-input v-model="form1.password2" placeholder="重新确认密码" password clearable border="surround"
shape='circle' :customStyle="{ backgroundColor: '#f6f6f6'}"></uv-input>
</view>
</view>
</view>
<!-- 按钮 -->
<view class="btn"
@click="submit">
<button class='a'>{{titleList[titleIndex]}}</button>
</view>
<!-- tab -->
<!-- <view class="bottomTab">
<span :class="titleIndex==0 ? 'tabbarItemActive' : 'tabbarItemNoActive'"
@click='changePage(0)'>注册账号</span>
<span style="color: #9c9fa4">|</span>
<span :class="titleIndex==1 ? 'tabbarItemActive' : 'tabbarItemNoActive'"
@click='changePage(1)'>账号登录</span>
<span style="color: #9c9fa4">|</span>
<span :class="titleIndex==2 ? 'tabbarItemActive' : 'tabbarItemNoActive'"
@click='changePage(2)'>忘记密码</span>
</view> -->
</view>
<configPopup ref="popup"></configPopup>
</view>
</template>
<script>
import configPopup from '@/components/config/configPopup.vue';
export default {
components: {
configPopup
},
onLoad(option) {
this.titleIndex = option.index || 1
},
data() {
return {
titleIndex: 0,
titleList: ['注册', '登录', '重置密码'],
checkboxValue: [],
form: {
account: '13135294009',
password: 'lzx123456',
},
form1: {
userName: '',
code: '',
password1: '',
password2: '',
},
tips: '获取验证码',
seconds: 60,
}
},
methods: {
submit(){
if(!this.checkboxValue.length){
return uni.showToast({
title: '请先同意隐私协议',
icon:'none'
})
}
if(this.$utils.verificationAll(this.form, {
account: '请输入账号',
password: '请输入密码',
})){
return
}
this.$store.commit('accountLogin', this.form)
},
//
changePage(index) {
this.titleIndex = index
},
confirm() {
},
codeChange(text) {
this.tips = text;
},
getCode() {
if (this.$refs.code.canGetCode) {
//
uni.showLoading({
title: '正在获取验证码'
})
setTimeout(() => {
uni.hideLoading();
// this.start()
uni.$uv.toast('验证码已发送');
//
this.$refs.code.start();
}, 2000);
} else {
uni.$uv.toast('请勿重复发送');
}
},
end() {
// uni.$uv.toast('');
},
start() {
// uni.$uv.toast('');
}
}
}
</script>
<style lang="scss" scoped>
* {
box-sizing: border-box;
}
.refundsOrExchange {
background-color: #FFF;
height: 100vh;
.frame {
background-color: #FFF;
.loginRegister {
display: flex;
flex-direction: column;
gap: 40rpx;
.title {
display: flex;
justify-content: center;
align-items: flex-end;
height: 10vh;
color: #000;
font-size: 40rpx;
font-weight: 700;
}
.userIamge {
display: flex;
justify-content: center;
height: 10vh;
>view:nth-of-type(1) {
width: 25%;
height: 100%;
border-radius: 50%;
overflow: hidden;
}
}
.form {
line-height: 50rpx;
>view:nth-of-type(1) {
padding: 20rpx 100rpx;
}
>view:nth-of-type(2) {
padding: 0 100rpx;
}
>view:nth-of-type(3) {
display: flex;
padding: 30rpx 100rpx 0 100rpx;
font-size: 22rpx
}
}
}
.btn {
// height: 5vh;
display: flex;
justify-content: center;
margin: 90rpx 0 0 0;
.a {
display: flex;
justify-content: center;
align-items: center;
width: 70%;
height: 80rpx;
color: #FFF;
background-color: $uni-color;
border: 1px solid red;
border-radius: 100rpx;
font-size: 30rpx;
}
}
.bottomTab {
display: flex;
justify-content: space-between;
height: 10vh;
padding: 0 80rpx;
margin-top: 30rpx;
.tabbarItemActive {
color: $uni-color;
}
.tabbarItemNoActive {
color: #9c9fa4;
}
}
.forgetPassword {
padding: 100rpx 40rpx 0 40rpx;
.title {
display: flex;
justify-content: center;
align-items: flex-end;
height: 10vh;
color: #000;
font-size: 40rpx;
font-weight: 700;
}
.form1 {
display: flex;
flex-direction: column;
gap: 30rpx;
margin-top: 20rpx;
padding: 20rpx 80rpx;
.userName {
// padding: 20rpx 100 rpx;
}
.code {
display: flex;
width: 100%;
.left {
width: 55%;
}
.right {
width: 45%;
height: 100%;
>view:nth-of-type(1) {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
}
}
}
.password1 {}
.password2 {}
}
}
}
}
</style>

+ 0
- 161
pages_order/auth/wxLogin.vue View File

@ -1,161 +0,0 @@
<template>
<view class="page_view">
<image class="bg" :src="configList.login_bg" mode="widthFix"></image>
<view class="content flex flex-column">
<image class="logo" :src="configList.app_logo" mode="widthFix"></image>
<!-- <image class="logo" src="@/static/image/icon.png" mode="widthFix"></image> -->
<view class="name">{{ configList.app_name || '' }}</view>
<button class="btn btn-login flex" @click="wxLogin" >授权手机号登录</button>
<button class="btn btn-cancel flex" @click="onCancel">暂不登录</button>
<view class="agreement">
<view>
<uv-checkbox-group
v-model="checkboxValue"
shape="circle"
>
<uv-checkbox
size="36rpx"
icon-size="36rpx"
activeColor="#014FA2"
:name="1"
></uv-checkbox>
</uv-checkbox-group>
</view>
<view class="desc">
阅读并同意我们的
<text class="highlight" @click="$refs.modal.open('config_privacy', '服务协议与隐私条款')">服务协议与隐私条款</text>
以及
<text class="highlight" @click="$refs.modal.open('config_agreement', '个人信息保护指引')">个人信息保护指引</text>
</view>
</view>
</view>
<agreementConfirmPopup ref="popup" @confirm="onConfirmAgreement"></agreementConfirmPopup>
<agreementModal ref="modal" @confirm="onConfirmAgreement"></agreementModal>
</view>
</template>
<script>
import agreementConfirmPopup from './agreementConfirmPopup.vue'
import agreementModal from '@/pages_order/components/agreementModal.vue'
export default {
name : 'Login',
components: {
agreementConfirmPopup,
agreementModal,
},
data() {
return {
checkboxValue : []
}
},
methods: {
wxLogin(){
if(!this.checkboxValue.length){
this.openAgreementConfirmPopup()
return
}
this.$store.commit('login')
},
openAgreementConfirmPopup() {
this.$refs.popup.open()
},
onConfirmAgreement(confirm) {
if (confirm) {
this.checkboxValue = [1]
} else {
this.checkboxValue = []
}
},
onCancel() {
uni.reLaunch({
url: '/pages/index/index'
})
},
}
}
</script>
<style scoped lang="scss">
.page_view {
width: 100vw;
height: 100vh;
}
.bg {
width: 100%;
height: auto;
}
.content {
transform: translateY(-8rpx);
width: 100%;
padding: 0 78rpx;
box-sizing: border-box;
}
.logo {
width: 100rpx;
height: auto;
}
.name {
margin-top: 20rpx;
font-size: 36rpx;
font-weight: 700;
color: #000000;
}
.btn {
width: 100%;
border-radius: 44rpx;
padding: 23rpx 0;
font-size: 32rpx;
line-height: 1.4;
font-family: PingFang SC;
&-login {
margin-top: 97rpx;
color: #FFFFFF;
background: #014FA2;
border: 2rpx solid #014FA2;
}
&-cancel {
margin-top: 66rpx;
color: #999999;
border: 2rpx solid #999999;
}
}
.agreement {
margin-top: 24rpx;
width: 100%;
display: flex;
justify-content: flex-start;
.desc {
font-family: PingFang SC;
font-size: 22rpx;
font-weight: 400;
line-height: 1.4;
color: #000000;
}
.highlight {
color: $uni-color;
}
}
</style>

+ 0
- 285
pages_order/auth/wxUserInfo.vue View File

@ -1,285 +0,0 @@
<template>
<view class="page__view">
<navbar />
<view class="flex flex-column header">
<image class="icon" :src="configList.app_logo" mode="widthFix"></image>
<!-- <image class="icon" src="@/static/image/icon.png" mode="widthFix"></image> -->
<view class="name">
{{ configList.app_name || '' }}
</view>
<view class="title">
申请获取你的头像昵称
</view>
</view>
<view class="form">
<view class="form-item">
<view class="label">
头像
</view>
<view class="content">
<button class="btn-avatar" :plain="true" :hairline="false" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image class="avatar" v-if="userInfoForm.headImage" :src="userInfoForm.headImage" mode=""></image>
<image class="avatar" v-else src="@/pages_order/static/auth/avatar-default.png" mode="scaleToFill"></image>
</button>
</view>
</view>
<view class="form-item">
<view class="label">
昵称
</view>
<view class="content">
<input type="nickname" placeholder="请输入昵称" style="text-align: right;" id="nickName"
placeholder-class="uni-placeholder"
v-model="userInfoForm.nickName"
/>
</view>
</view>
<view class="form-item">
<view class="label">
手机号
</view>
<view class="flex content" style="justify-content: flex-end; column-gap: 31rpx;">
<input
v-model="userInfoForm.phone"
style="text-align: right;"
disabled
/>
<button
:plain="true" :hairline="false"
class="btn-phone"
open-type="getPhoneNumber"
@getphonenumber="getPhone"
>
获取手机号
</button>
</view>
</view>
</view>
<view class="footer">
<button class="btn" @click="submit">
确定
</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
userInfoForm: {
headImage: '',
nickName: '',
phone: '',
}
};
},
onShow() {},
onLoad() {
this.userInfoForm.nickName = this.userInfo.nickName || ''
this.userInfoForm.headImage = this.userInfo.headImage || ''
},
computed: {},
methods: {
onChooseAvatar(res) {
this.$Oss.ossUpload(res.target.avatarUrl)
.then(url => {
this.userInfoForm.headImage = url
})
},
getPhone(e){
this.$api('bindPhone', {
phoneCode : e.detail.code
}, res => {
if(res.code == 200){
let phoneObj = JSON.parse(res.result)
if(phoneObj.errmsg == 'ok'){
this.userInfoForm.phone = phoneObj.phone_info.phoneNumber
}else{
uni.showModal({
title: phoneObj.errmsg
})
}
}
})
},
submit() {
let self = this
uni.createSelectorQuery().in(this)
.select("#nickName")
.fields({
properties: ["value"],
})
.exec((res) => {
const nickName = res?.[0]?.value
self.userInfoForm.nickName = nickName
if (self.$utils.verificationAll(self.userInfoForm, {
headImage: '请选择头像',
nickName: '请填写昵称',
phone: '请填写手机号',
})) {
return
}
self.$api('updateInfo', {
headImage : self.userInfoForm.headImage,
nickName : self.userInfoForm.nickName,
phone : self.userInfoForm.phone,
}, res => {
if (res.code == 200) {
uni.reLaunch({
url:'/pages/index/index'
})
}
})
})
},
}
}
</script>
<style lang="scss" scoped>
.page__view {
display: flex;
justify-content: flex-start;
align-items: center;
height: 100vh;
flex-direction: column;
position: relative;
.header{
padding: 187rpx 0 106rpx 0;
.icon {
width: 100rpx;
height: auto;
}
.name {
margin: 20rpx 0 14rpx 0;
font-size: 36rpx;
font-family: PingFang SC, PingFang SC-Bold;
font-weight: 700;
text-align: center;
color: #000000;
}
.title {
font-size: 30rpx;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: 400;
color: #000000;
}
}
.form {
padding: 0 48rpx;
box-sizing: border-box;
width: 100%;
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
min-height: 119rpx;
padding: 0 22rpx 0 13rpx;
position: relative;
border-top: 1rpx solid rgba($color: #C7C7C7, $alpha: 0.33);
&:last-child {
border-bottom: 1rpx solid rgba($color: #C7C7C7, $alpha: 0.33);
}
.label {
white-space: nowrap;
font-size: 32rpx;
font-weight: 400;
text-align: left;
color: #000000;
}
.content {
flex: 1;
text-align: right;
}
}
.btn-avatar {
background: transparent;
border: none;
border-radius: none;
box-shadow: none;
padding: 0;
margin: 0;
font-size: 0;
text-align: right;
}
.avatar {
display: inline-block;
width: 97rpx;
height: 97rpx;
}
.btn-phone {
display: inline-block;
width: auto;
margin: 0;
padding: 23rpx 33rpx;
font-size: 30rpx;
line-height: 1.4;
color: #FFFFFF;
background: #014FA2;
border: none;
border-radius: 38rpx;
}
}
.btn {
text-align: center;
margin-top: 155rpx;
width: 80%;
height: 100rpx;
border-radius: 50rpx;
background-image: linear-gradient(to right, #84A73F, #D8FF8F);
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50rpx;
border: none;
}
}
.footer {
margin-top: 200rpx;
width: 100%;
padding: 0 78rpx;
box-sizing: border-box;
.btn {
width: 100%;
padding: 25rpx 0;
box-sizing: border-box;
font-size: 32rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 41rpx;
}
}
</style>

+ 0
- 101
pages_order/components/agreementModal.vue View File

@ -1,101 +0,0 @@
<template>
<view>
<uv-modal ref="modal" :showConfirmButton="false">
<view class="modal__view">
<view class="header">
{{ title }}
</view>
<view class="content">
<uv-parse :content="content"></uv-parse>
</view>
<view class="footer">
<button class="btn" @click="onConfirm(false)">拒绝</button>
<button class="btn btn-confirm" @click="onConfirm(true)">同意</button>
</view>
</view>
</uv-modal>
<configPopup ref="popup"></configPopup>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
key: '',
title : '',
content : '',
}
},
computed : {
...mapState(['configList'])
},
methods: {
open(key, title) {
this.key = key
this.title = title
this.content = this.configList[key]
this.$refs.modal.open()
},
onConfirm(confirm) {
this.$emit('confirm', confirm, this.key)
this.$refs.modal.close()
},
},
}
</script>
<style lang="scss" scoped>
.modal__view {
width: 100%;
display: flex;
flex-direction: column;
padding-top: 40rpx;
}
.header {
text-align: center;
font-size: 34rpx;
font-family: PingFang SC;
font-weight: 600;
line-height: 1.4;
color: #181818;
}
.content {
padding: 8rpx 32rpx 40rpx 32rpx;
max-height: 70vh;
overflow-y: scroll;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.7;
text-align: left;
color: #636465;
}
.footer {
display: flex;
border-top: 1rpx solid #EEEEEE;
.btn {
flex: 1;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 22rpx 32rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.4;
color: #393939;
&-confirm {
color: $uni-color;
border-left: 1rpx solid #EEEEEE;
}
}
}
</style>

+ 0
- 47
pages_order/components/formTextarea.vue View File

@ -1,47 +0,0 @@
<template>
<uv-textarea
:value="value"
@input="$emit('input', $event)"
:placeholder="placeholder"
:height="height"
border="none"
:customStyle="{
padding: '0',
}"
:placeholderStyle="{
color: '#999999',
fontSize: '28rpx',
}"
:textStyle="{
fontSize: '28rpx',
}"
></uv-textarea>
</template>
<script>
export default {
props: {
value: {
default: null
},
placeholder: {
type: String,
default: '请输入'
},
height: {
type: String,
default: '462rpx'
},
},
data() {
return {
}
},
methods: {
},
}
</script>
<style scoped lang="scss">
</style>

+ 0
- 102
pages_order/components/formUpload.vue View File

@ -1,102 +0,0 @@
<template>
<view>
<uv-upload
:fileList="displayFileList"
:accept="accept"
:maxCount="maxCount"
:width="width"
:height="height"
@afterRead="afterRead"
@delete="deleteFile"
>
<button class="flex btn">
<image class="icon" src="@/pages_order/static/feedback/icon-camera.png" mode="widthFix"></image>
</button>
</uv-upload>
</view>
</template>
<script>
export default {
props: {
value: {
type: Array,
default() {
return []
}
},
accept: {
type: String,
default: 'image' // all | media | image | file | video
},
width: {
type: Number | String,
default: 133,
},
height: {
type: Number | String,
default: 133,
},
maxCount: {
type: Number | String,
default: 100,
}
},
data() {
return {
}
},
computed: {
fileList: {
set(val) {
this.$emit('input', val)
},
get() {
return this.value
}
},
displayFileList() {
return this.fileList.map(url => ({ url }))
},
},
watch: {
fileList: {
handler(val) {
console.log('watch fileList', val)
},
deep: true,
},
displayFileList: {
handler(val) {
console.log('watch displayFileList', val)
},
deep: true,
},
},
methods: {
deleteFile(e){
console.log('deleteFile', e)
const fileList = [...this.fileList]
fileList.splice(e.index, 1)
this.fileList = fileList
},
afterRead(e){
this.$Oss.ossUpload(e.file.url).then(url => {
this.fileList = this.fileList.concat(url)
})
},
},
}
</script>
<style scoped lang="scss">
.btn {
border-radius: 0;
.icon {
width: 133rpx;
height: auto;
}
}
</style>

+ 0
- 301
pages_order/feedback/index copy.vue View File

@ -1,301 +0,0 @@
<template>
<view class="page__view">
<navbar title="意见反馈" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
<view class="bg">
<view class="title">Hello</view>
<view class="desc">有什么好的建议可以告诉我们哦</view>
</view>
<view class="main">
<view class="form">
<uv-form
ref="form"
:model="form"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="textDetails" :customStyle="formItemStyle">
<view class="card">
<view class="editor-header">
<view class="editor-header-content">
<view>反馈内容</view>
<view class="editor-icon">
<uv-icon name="star-fill" color="#FFFFFF" size="26rpx"></uv-icon>
</view>
</view>
</view>
<view class="editor__view">
<editor id="editor" class="editor"
placeholder="请填写10个字以上的内容,以便我们为您提供更好的服务"
@ready="onEditorReady"
@input="onEditroInput"
></editor>
<view class="editor-tools">
<button @click="insertImage" plain class="flex btn">
<!-- todo: 缺切图 -->
<uv-icon name="camera-fill" color="#014FA2" size="56rpx"></uv-icon>
</button>
</view>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="phone" :customStyle="formItemStyle">
<view class="flex card phone">
<view class="label">联系电话</view>
<input
v-model="form.phone"
placeholder-style="color: #999999; font-size: 28rpx;"
placeholder="请输入手机号"
/>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
form: {
textDetails: null,
phone: null,
},
formItemStyle: { padding: 0 },
}
},
onReady() {
this.$refs.form.setRules(this.getRules());
},
methods: {
onEditorReady() {
uni.createSelectorQuery().select('#editor').context((res) => {
this.editorCtx = res.context
}).exec()
},
onEditroInput(e) {
const { text } = e.detail
this.descLen = text?.length || 0
},
insertImage() {
uni.chooseImage({
count: 1,
success: (res) => {
// this.editorCtx.insertImage({
// src: res.tempFilePaths[0],
// alt: '',
// })
// todo: check
this.$Oss.ossUpload(res.tempFilePaths[0]).then(url => {
this.editorCtx.insertImage({
src: url,
alt: '图像',
})
})
}
})
},
setEditorContents(html) {
if (!this.editorCtx) {
setTimeout(() => {
this.setEditorContents(html)
}, 200)
return
}
this.editorCtx.setContents({ html })
},
getEditorContents() {
return new Promise((resolve, reject) => {
this.editorCtx.getContents({
success: (e) => {
const { html, text } = e
resolve({ html, text })
},
fail: () => {
reject()
}
})
})
},
getRules() {
const textDetailsValidator = async (rule, value, callback) => {
const textDetails = (await this.getEditorContents())?.html
if (textDetails) {
callback()
return
}
callback(new Error('请填写10个字以上的内容,以便我们为您提供更好的服务'))
}
return {
'phone': {
type: 'string',
required: true,
message: '请输入手机号',
},
'textDetails': {
asyncValidator: textDetailsValidator,
},
}
},
async onSubmit(headImage) {
try {
await this.$refs.form.validate()
const textDetails = (await this.getEditorContents())?.html
const {
phone,
} = this.form
const params = {
phone,
textDetails,
}
// todo
// await this.$fetch('saveOrUpdateArticleShare', params)
uni.showToast({
title: '提交成功',
icon: 'none'
})
setTimeout(uni.navigateBack, 1000, -1)
} catch (err) {
}
},
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
}
.bg {
width: 100%;
height: 501rpx;
padding-top: 203rpx;
box-sizing: border-box;
color: #FFFFFF;
background: linear-gradient(164deg, #014FA2 30%, #4C8FD6);
.title {
padding: 0 73rpx;
font-size: 64rpx;
font-weight: 600;
}
.desc {
margin-top: 18rpx;
padding: 0 68rpx;
box-sizing: border-box;
font-size: 28rpx;
}
}
.main {
width: 100%;
padding: 0 28rpx;
box-sizing: border-box;
background: #F5F5F5;
}
.form {
// transform: translateY(-98rpx);
transform: translateY(-46rpx);
&-item {
& + & {
margin-top: 36rpx;
}
}
}
.editor__view {
padding: 43rpx 30rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
}
.editor-header {
position: absolute;
top: 0;
left: 12rpx;
transform: translateY(-100%);
// margin-left: 12rpx;
&-content {
position: relative;
padding: 9rpx 20rpx 3rpx 20rpx;
font-size: 28rpx;
font-weight: 600;
color: #FFFFFF;
border-top-left-radius: 30rpx;
background: linear-gradient(to right, #014FA2, #6A9ACE);
}
}
.editor-icon {
position: absolute;
top: 0;
right: 0;
transform: translate(30rpx, -4rpx);
}
.editor {
height: 462rpx;
&-tools {
padding: 0 7rpx;
.btn {
width: 133rpx;
height: 133rpx;
border: 2rpx dashed #014FA2;
}
}
}
.card {
position: relative;
}
.phone {
justify-content: flex-start;
padding: 44rpx 27rpx;
column-gap: 31rpx;
background: #FFFFFF;
border-radius: 15rpx;
.label {
font-size: 28rpx;
color: #000000;
}
}
</style>

+ 0
- 262
pages_order/feedback/index.vue View File

@ -1,262 +0,0 @@
<template>
<view class="page__view">
<navbar title="意见反馈" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
<image class="bg" :src="configList.feedback_bg" mode="widthFix"></image>
<!-- <view class="bg">
<view class="title">Hello</view>
<view class="desc">有什么好的建议可以告诉我们哦</view>
</view> -->
<view class="main">
<view class="form">
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="content" :customStyle="formItemStyle">
<view class="card feedback">
<view class="feedback-header">
<view class="feedback-header-content">
<view>反馈内容</view>
<view class="feedback-icon">
<image class="icon" src="@/pages_order/static/feedback/icon-star.png" mode="widthFix"></image>
</view>
</view>
</view>
<view>
<formTextarea v-model="form.content" placeholder="请填写10个字以上的内容,以便我们为您提供更好的服务"></formTextarea>
</view>
<view>
<formUpload v-model="form.images"></formUpload>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="phone" :customStyle="formItemStyle">
<view class="flex card phone">
<view class="label">联系电话</view>
<input
v-model="form.phone"
placeholder-style="color: #999999; font-size: 28rpx;"
placeholder="请输入手机号"
/>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
</view>
<view class="bottom">
<button class="btn" @click="onSubmit">提交</button>
</view>
</view>
</template>
<script>
import util from '@/utils/utils.js'
import formTextarea from '@/pages_order/components/formTextarea.vue'
import formUpload from '@/pages_order/components/formUpload.vue'
export default {
components: {
formTextarea,
formUpload,
},
data() {
return {
form: {
content: null,
images: [],
phone: null,
},
rules: {
'content': {
type: 'string',
required: true,
message: '请填写10个字以上的内容,以便我们为您提供更好的服务',
},
'phone': {
type: 'string',
required: true,
message: '请输入正确的手机号',
validator: (rule, value, callback) => {
return util.verificationPhone(value)
},
},
},
formItemStyle: { padding: 0 },
}
},
onReady() {
this.$refs.form.setRules(this.rules);
},
methods: {
async onSubmit() {
try {
await this.$refs.form.validate()
const {
content,
images,
phone,
} = this.form
const params = {
content,
image: images.join(','),
phone,
}
await this.$fetch('addFeedback', params)
uni.showToast({
title: '提交成功',
icon: 'none'
})
setTimeout(uni.navigateBack, 1000, -1)
} catch (err) {
}
},
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
}
.bg {
width: 100%;
height: auto;
min-height: 501rpx;
// height: 501rpx;
// padding-top: 203rpx;
// box-sizing: border-box;
// color: #FFFFFF;
// background: linear-gradient(164deg, #014FA2 30%, #4C8FD6);
// .title {
// padding: 0 73rpx;
// font-size: 64rpx;
// font-weight: 600;
// }
// .desc {
// margin-top: 18rpx;
// padding: 0 68rpx;
// box-sizing: border-box;
// font-size: 28rpx;
// }
}
.main {
width: 100%;
padding: 0 28rpx 200rpx 28rpx;
box-sizing: border-box;
background: #F5F5F5;
}
.form {
// transform: translateY(-98rpx);
transform: translateY(-46rpx);
&-item {
& + & {
margin-top: 36rpx;
}
}
}
.card {
position: relative;
background: #FFFFFF;
border-radius: 15rpx;
}
.feedback {
padding: 43rpx 31rpx;
}
.feedback-header {
position: absolute;
top: 0;
left: 12rpx;
transform: translateY(-100%);
// margin-left: 12rpx;
&-content {
position: relative;
padding: 9rpx 20rpx 3rpx 20rpx;
font-size: 28rpx;
font-weight: 600;
color: #FFFFFF;
border-top-left-radius: 30rpx;
background: linear-gradient(to right, #014FA2, #6A9ACE);
}
}
.feedback-icon {
position: absolute;
top: 0;
right: 0;
transform: translate(30rpx, -10rpx);
.icon {
width: 26rpx;
height: auto;
}
}
.phone {
justify-content: flex-start;
padding: 44rpx 27rpx;
column-gap: 31rpx;
.label {
font-size: 28rpx;
color: #000000;
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
padding: 0 35rpx 56rpx 35rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 35rpx);
box-sizing: border-box;
.btn {
width: 100%;
padding: 29rpx 0;
box-sizing: border-box;
font-size: 30rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
}
</style>

+ 0
- 85
pages_order/report/codeErrorPopup.vue View File

@ -1,85 +0,0 @@
<template>
<uv-popup
ref="popup"
:overlayOpacity="0"
mode="center"
bgColor="none"
>
<view class="flex flex-column popup__view">
<text class="title">兑换码输入有误请与客服确认</text>
<text class="desc">联系客服获取抵扣码</text>
<image class="img" :src="configList.customer_service_qrcode" :show-menu-by-longpress="true" mode="widthFix"></image>
<button class="btn" @click="close">好的</button>
</view>
</uv-popup>
</template>
<script>
import { mapState } from 'vuex'
export default {
props: {
src: {
type: String,
default: null
}
},
data() {
return {
}
},
computed : {
...mapState(['configList'])
},
methods: {
open() {
this.$refs.popup.open();
},
close() {
this.$refs.popup.close();
},
},
}
</script>
<style scoped lang="scss">
.popup__view {
position: relative;
width: 600rpx;
min-height: 582rpx;
padding: 60rpx 59rpx 40rpx 59rpx;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 16rpx;
}
.title {
font-size: 30rpx;
font-weight: 600;
color: #000000;
}
.desc {
margin-top: 48rpx;
font-size: 28rpx;
font-weight: 500;
color: #000000;
}
.img {
margin: 40rpx 0 75rpx 0;
width: 156rpx;
height: auto;
min-height: 156rpx;
}
.btn {
width: 100%;
padding: 18rpx 0;
box-sizing: border-box;
font-size: 30rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 40rpx;
}
</style>

+ 0
- 299
pages_order/report/pay.vue View File

@ -1,299 +0,0 @@
<template>
<view class="page__view">
<navbar title="支付" leftClick @leftClick="$utils.navigateBack" />
<view class="flex flex-column info">
<view>实付金额</view>
<view class="flex price">
<view>¥</view>
<view class="highlight">{{ payAmount }}</view>
</view>
<view class="flex flex-column contact">
<view>联系客服获取抵扣码</view>
<image class="qr" :src="configList.customer_service_qrcode" :show-menu-by-longpress="true" mode="widthFix"></image>
</view>
</view>
<view class="form">
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="payment" :customStyle="formItemStyle">
<view class="form-item-label">选择支付方式</view>
<view class="form-item-content">
<uv-radio-group
v-model="form.payment"
placement="column"
shape="circle"
size="30rpx"
iconSize="30rpx"
activeColor="#014FA2"
>
<view class="payment">
<view class="flex payment-content">
<view class="flex payment-content-info">
<image class="icon" src="@/pages_order/static/report/icon-wx.png" mode="widthFix"></image>
<view>微信支付</view>
</view>
<view>
<uv-radio :name="0"></uv-radio>
</view>
</view>
</view>
<view class="payment">
<view class="flex payment-content">
<view class="flex payment-content-info">
<image class="icon" src="@/pages_order/static/report/icon-coupon.png" mode="widthFix"></image>
<view>兑换码抵扣支付</view>
</view>
<view>
<uv-radio :name="1"></uv-radio>
</view>
</view>
</view>
</uv-radio-group>
</view>
</uv-form-item>
</view>
<view class="form-item is-child" v-if="form.payment == 1">
<uv-form-item prop="code" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">兑换码</view>
<view class="form-item-content">
<input
v-model="form.code"
placeholder="请输入兑换码"
placeholderStyle="color: #999999; font-size: 30rpx; font-weight: 400;"
/>
</view>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
<view class="bottom">
<button class="btn" @click="onPay">立即支付</button>
</view>
<codeErrorPopup ref="codeErrorPopup"></codeErrorPopup>
</view>
</template>
<script>
import codeErrorPopup from './codeErrorPopup.vue'
export default {
components: {
codeErrorPopup,
},
data() {
return {
batchNo: null,
form: {
payment: 0,
code: null,
},
rules: {
'payment': {
type: 'number',
required: false,
message: '请选择支付方式',
},
'code': {
type: 'string',
required: true,
message: '请输入兑换码',
},
},
formItemStyle: { padding: 0 },
}
},
computed: {
payAmount() {
return Number(this.configList.pay_amount)
}
},
onLoad(arg) {
const { batchNo } = arg
this.batchNo = batchNo
},
methods: {
async onPay() {
try {
await this.$refs.form.validate()
const {
payment,
code,
} = this.form
const params = {
batchNo: this.batchNo,
payAmount: this.payAmount,
}
if (payment == 1) { //
const infoRes = await this.$fetch('queryCodeById', { code }, false, null, true)
const { result: infoResult } = infoRes
if (!infoResult || infoResult?.isUse !== '0') {
this.$refs.codeErrorPopup.open()
return
}
params.discountAmount = infoResult.discountAmount
params.payAmount -= params.discountAmount
params.code = code
}
const result = await this.$fetch('createOrder', params)
await uni.requestPaymentWxPay({ result })
uni.showToast({
title: '支付成功',
icon: 'none'
})
setTimeout(() => {
uni.redirectTo({
url: `/pages_order/report/userInfo?batchNo=${this.batchNo}`
})
}, 700)
} catch (err) {
}
},
},
}
</script>
<style scoped lang="scss">
.info {
width: 100%;
padding: 96rpx 62rpx 51rpx 62rpx;
box-sizing: border-box;
font-size: 28rpx;
line-height: 50rpx;
color: #000000;
.price {
margin-top: 23rpx;
align-items: baseline;
column-gap: 13rpx;
font-size: 51rpx;
line-height: 72rpx;
color: #000000;
.highlight {
font-size: 78rpx;
line-height: 110rpx;
}
}
.contact {
margin-top: 52rpx;
row-gap: 40rpx;
width: 100%;
padding: 30rpx 0 26rpx 0;
box-sizing: border-box;
border: 1rpx dashed #014FA2;
.qr {
width: 157rpx;
height: auto;
}
}
}
.form {
&-item {
&-label {
padding: 0 38rpx;
font-size: 28rpx;
line-height: 50rpx;
color: #000000;
}
&-content {
}
}
}
.payment {
&:first-child {
margin-top: 24rpx;
}
& + & {
border-top: 20rpx solid #F7F7F7;
}
&-content {
justify-content: space-between;
padding: 32rpx 60rpx 32rpx 50rpx;
&-info {
column-gap: 15rpx;
font-size: 30rpx;
color: #000000;
.icon {
width: 58rpx;
height: auto;
}
}
}
}
.form-item.is-child {
padding: 22rpx 60rpx 0 123rpx;
.form-item-label,
.form-item-content {
padding: 0;
}
.form-item-label {
padding-right: 16rpx;
font-size: 30rpx;
}
.form-item-content {
flex: 1;
padding: 11rpx;
background: #F7F7F7;
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 35rpx 56rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 35rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 29rpx 0;
font-size: 30rpx;
line-height: 1.5;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
}
</style>

+ 0
- 262
pages_order/report/userInfo.vue View File

@ -1,262 +0,0 @@
<template>
<view class="page__view">
<navbar title="支付" leftClick @leftClick="$utils.navigateBack" />
<view class="status">
<view class="flex status-content">
<uv-icon name="checkmark-circle-fill" color="#014FA2" size="48rpx"></uv-icon>
<view>支付成功</view>
</view>
</view>
<view class="tips">
<view class="flex tips-content">
<!-- <uv-icon name="error-circle" color="#014FA2" size="36rpx"></uv-icon> -->
<image class="icon" src="@/pages_order/static/report/icon-info.png" mode="widthFix"></image>
<view>请如实填写以下信息方可获取答题情况生成风险测评报告</view>
</view>
</view>
<view class="form">
<view class="flex form-header">
<view class="line"></view>
<view>基本信息</view>
</view>
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="name" :customStyle="formItemStyle">
<view class="flex row">
<view class="row-label">姓名</view>
<view class="row-content">
<input
v-model="form.name"
placeholder="请输入您的姓名"
:placeholderStyle="placeholderStyle"
/>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="phone" :customStyle="formItemStyle">
<view class="flex row">
<view class="row-label">手机号码</view>
<view class="row-content">
<input
v-model="form.phone"
placeholder="请输入您的手机号"
:placeholderStyle="placeholderStyle"
/>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="company" :customStyle="formItemStyle">
<view class="flex row">
<view class="row-label is-required">公司名称</view>
<view class="row-content">
<input
v-model="form.company"
placeholder="请选输入公司全称"
:placeholderStyle="placeholderStyle"
/>
</view>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
<view class="bottom">
<button :class="['btn', disabled ? 'is-disabled' : '']" @click="onCreateReport">生成报告</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
id: null,
form: {
name: '',
phone: '',
company: '',
},
rules: {
'company': {
type: 'string',
required: true,
message: '请填写公司名称~',
},
},
formItemStyle: { padding: 0 },
placeholderStyle: 'color: #BDBDBD; font-size: 28rpx; font-weight: 400;'
}
},
computed: {
disabled() {
const { name, phone, company } = this.form
return !company
}
},
onLoad(arg) {
const { batchNo } = arg
this.batchNo = batchNo
},
methods: {
async onCreateReport() {
try {
await this.$refs.form.validate()
const { name, phone, company } = this.form
const params = {
batchNo: this.batchNo,
name,
phone,
company,
}
await this.$fetch('addReport', params)
uni.redirectTo({
url: `/pages_order/report/index?batchNo=${this.batchNo}`
})
} catch (err) {
}
},
},
}
</script>
<style scoped lang="scss">
.status {
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
&-content {
width: 100%;
padding: 157rpx 0 84rpx 0;
box-sizing: border-box;
column-gap: 18rpx;
font-size: 48rpx;
font-weight: 600;
color: #000000;
border-bottom: 1rpx dashed #E2EAF1;
}
}
.tips {
width: 100%;
padding: 68rpx 24rpx 35rpx 24rpx;
box-sizing: border-box;
&-content {
justify-content: flex-start;
column-gap: 15rpx;
width: 100%;
padding: 13rpx 22rpx;
box-sizing: border-box;
font-size: 22rpx;
line-height: 40rpx;
color: #014FA2;
background: rgba($color: #014FA2, $alpha: 0.16);
border-radius: 11rpx;
.icon {
width: 36rpx;
height: auto;
}
}
}
.form {
padding: 0 18rpx;
&-header {
margin-bottom: 28rpx;
padding: 0 18rpx;
justify-content: flex-start;
column-gap: 7rpx;
font-size: 30rpx;
font-weight: 600;
color: #000000;
.line {
width: 9rpx;
height: 33rpx;
background: #014FA2;
border-radius: 6rpx;
}
}
&-item {
border-bottom: 0.5rpx solid rgba($color: #707070, $alpha: 0.14);
}
}
.row {
justify-content: space-between;
padding: 36rpx 30rpx 22rpx 24rpx;
&-label {
position: relative;
font-size: 30rpx;
color: #000000;
&.is-required:after {
content: '*';
position: absolute;
top: 0;
left: 0;
font-size: 15rpx;
line-height: 42rpx;
color: #FF3838;
}
}
&-content {
/deep/ input {
text-align: right;
}
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 35rpx 56rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 35rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 29rpx 0;
font-size: 30rpx;
line-height: 1.5;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
&.is-disabled {
background: #999999;
}
}
}
</style>

+ 0
- 55
pages_order/service/commonQuestion.vue View File

@ -1,55 +0,0 @@
<template>
<view class="page__view">
<navbar title="常见问题" leftClick @leftClick="$utils.navigateBack" />
<view class="main">
<view class="title">{{ commonQuestion.question }}</view>
<view class="content">
<uv-parse :content="commonQuestion.answer"></uv-parse>
</view>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
detail: {},
}
},
computed: {
...mapState(['commonQuestion']),
},
onLoad(arg) {
const { id } = arg
this.getData(id)
},
methods: {
async getData(id) {
// todo: fetch by id
},
},
}
</script>
<style scoped lang="scss">
.main {
padding: 39rpx 30rpx;
}
.title {
text-align: center;
font-size: 30rpx;
font-weight: 600;
color: #000000;
}
.content {
margin-top: 50rpx;
}
</style>

+ 0
- 198
pages_order/service/index.vue View File

@ -1,198 +0,0 @@
<template>
<view class="page__view">
<navbar title="咨询客服" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
<image class="bg" :src="configList.customer_service_bg" mode="widthFix"></image>
<!-- <view class="flex bg">
<view class="flex bg-content">
<view class="text">
<view class="title">Hi,有什么可以帮您</view>
<view class="desc">
<view class="line">工作时间</view>
<view class="line">8:00-12:00 13:00-17:30</view>
</view>
</view>
<image class="icon" src="@/pages_order/static/service/icon-service.png" mode="widthFix"></image>
</view>
</view> -->
<view class="main">
<view class="content">
<view class="flex card concat">
<button plain class="flex flex-column btn" open-type="contact">
<image class="icon" src="@/pages_order/static/service/icon-message.png" mode="widthFix"></image>
<view>联系客服</view>
</button>
<button plain class="flex flex-column btn" @click="openQrPopup">
<image class="icon" src="@/pages_order/static/service/icon-wx.png" mode="widthFix"></image>
<view>添加微信</view>
</button>
<button plain class="flex flex-column btn" @click="openPhonePopup">
<image class="icon" src="@/pages_order/static/service/icon-phone.png" mode="widthFix"></image>
<view>电话咨询</view>
</button>
</view>
<view class="card question">
<view class="card-header">常见问题</view>
<view class="flex row" v-for="item in list" :key="item.id" @click="jumpToQuestion(item.id)">
<view>{{ item.question }}</view>
<uv-icon name="arrow-right" color="#999999" size="33rpx"></uv-icon>
</view>
</view>
</view>
</view>
<popupQrCode ref="popupQrCode"></popupQrCode>
<popupPhone ref="popupPhone"></popupPhone>
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import popupQrCode from './popupQrCode.vue'
import popupPhone from './popupPhone.vue'
export default {
mixins: [mixinsList],
components: {
popupQrCode,
popupPhone,
},
data() {
return {
list: [],
mixinsListApi: 'queryFaqList',
}
},
methods: {
openQrPopup() {
this.$refs.popupQrCode.open()
},
openPhonePopup() {
this.$refs.popupPhone.open()
},
jumpToQuestion(id) {
let data = this.list.find(item => item.id === id)
this.$store.commit('setCommonQuestion', data)
uni.navigateTo({
url: `/pages_order/service/commonQuestion?id=${id}`
})
},
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
}
.bg {
width: 100%;
height: auto;
min-height: 501rpx;
// width: 100%;
// height: 501rpx;
// background: linear-gradient(160deg, #014FA2 36%, #4C8FD6);
// padding: 0 104rpx 90rpx 65rpx;
// box-sizing: border-box;
// align-items: flex-end;
// &-content {
// width: 100%;
// justify-content: space-between;
// }
// .text {
// padding: 26rpx 0 34rpx 0;
// color: #FFFFFF;
// .title {
// font-size: 36rpx;
// font-weight: 600;
// }
// .desc {
// margin-top: 13rpx;
// font-size: 22rpx;
// .line + .line {
// margin-top: 11rpx;
// }
// }
// }
// .icon {
// width: 168rpx;
// height: auto;
// }
}
.main {
width: 100%;
padding: 0 28rpx 28rpx 28rpx;
box-sizing: border-box;
background: #F5F5F5;
.content {
transform: translateY(-64rpx);
}
}
.card {
width: 100%;
background: #FFFFFF;
border-radius: 15rpx;
}
.card.concat {
justify-content: space-between;
width: 100%;
padding: 55rpx 64rpx 26rpx 64rpx;
box-sizing: border-box;
.btn {
justify-content: space-between;
font-size: 28rpx;
color: #000000;
border: none;
.icon {
width: 66rpx;
height: auto;
}
}
}
.card.question {
margin-top: 25rpx;
padding: 34rpx 19rpx;
box-sizing: border-box;
.card-header {
padding: 0 11rpx 11rpx 11rpx;
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
.row {
margin-top: 22rpx;
justify-content: space-between;
padding: 17rpx 14rpx 17rpx 23rpx;
font-size: 30rpx;
color: #000000;
border-bottom: 0.5rpx solid rgba($color: #707070, $alpha: 0.1);
}
}
</style>

+ 0
- 119
pages_order/service/popupPhone.vue View File

@ -1,119 +0,0 @@
<template>
<uv-popup
ref="popup"
:overlayOpacity="0"
mode="center"
bgColor="none"
>
<view class="popup__view">
<image class="bg" src="@/pages_order/static/service/bg-popup-phone.png" mode="widthFix"></image>
<view class="flex flex-column content">
<text class="title">电话咨询</text>
<view class="flex phone">
<view class="flex icon" @click="onCall">
<image class="img" src="@/pages_order/static/service/icon-phone.png" mode="widthFix"></image>
</view>
<view>{{ phone }}</view>
</view>
<button class="btn" @click="onCopy()">复制手机号</button>
</view>
</view>
</uv-popup>
</template>
<script>
import { mapState } from 'vuex'
import utils from '@/utils/utils.js'
export default {
data() {
return {
phone: '',
}
},
computed : {
...mapState(['configList'])
},
methods: {
open() {
this.phone = this.configList.customer_service_phone
this.$refs.popup.open();
},
close() {
this.$refs.popup.close();
},
onCall() {
uni.makePhoneCall({
phoneNumber: this.phone,
success() {
console.log('安卓拨打成功');
},
fail() {
console.log('安卓拨打失败');
}
})
},
onCopy() {
utils.copyText(this.phone)
},
},
}
</script>
<style scoped lang="scss">
.popup__view {
position: relative;
width: 684rpx;
min-height: 701rpx;
background: #FFFFFF;
border-radius: 16rpx;
}
.bg {
width: 100%;
height: auto;
}
.content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 69rpx 0;
box-sizing: border-box;
justify-content: space-between;
}
.title {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
.phone {
margin: 238rpx 0 122rpx 0;
column-gap: 21rpx;
font-size: 32rpx;
font-weight: 600;
color: #000000;
.icon {
width: 60rpx;
height: 60rpx;
.img {
width: 100%;
height: 100%;
}
}
}
.btn {
padding: 29rpx 202rpx;
font-size: 30rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
</style>

+ 0
- 86
pages_order/service/popupQrCode.vue View File

@ -1,86 +0,0 @@
<template>
<uv-popup
ref="popup"
:overlayOpacity="0"
mode="center"
bgColor="none"
>
<view class="popup__view">
<image class="bg" src="@/pages_order/static/service/bg-popup-qr.png" mode="widthFix"></image>
<view class="flex flex-column content">
<text class="title">扫码添加微信</text>
<image class="img" :src="configList.customer_service_qrcode" :show-menu-by-longpress="true"></image>
<button class="btn" @click="close">已截图</button>
</view>
</view>
</uv-popup>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
}
},
computed : {
...mapState(['configList'])
},
methods: {
open() {
this.$refs.popup.open();
},
close() {
this.$refs.popup.close();
},
},
}
</script>
<style scoped lang="scss">
.popup__view {
position: relative;
width: 684rpx;
min-height: 826rpx;
background: #FFFFFF;
border-radius: 16rpx;
}
.bg {
width: 100%;
height: auto;
}
.content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 71rpx 0 23rpx 0;
box-sizing: border-box;
justify-content: space-between;
}
.title {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
.img {
margin: 156rpx 0 73rpx 0;
width: 360rpx;
height: auto;
min-height: 360rpx;
}
.btn {
padding: 29rpx 202rpx;
font-size: 30rpx;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
</style>

BIN
pages_order/static/auth/avatar-default.png View File

Before After
Width: 99  |  Height: 99  |  Size: 2.2 KiB

BIN
pages_order/static/feedback/icon-camera.png View File

Before After
Width: 133  |  Height: 133  |  Size: 2.3 KiB

BIN
pages_order/static/feedback/icon-star.png View File

Before After
Width: 27  |  Height: 27  |  Size: 588 B

BIN
pages_order/static/report/icon-coupon.png View File

Before After
Width: 58  |  Height: 45  |  Size: 2.7 KiB

BIN
pages_order/static/report/icon-info.png View File

Before After
Width: 36  |  Height: 36  |  Size: 1.7 KiB

BIN
pages_order/static/report/icon-wx.png View File

Before After
Width: 54  |  Height: 45  |  Size: 2.1 KiB

BIN
pages_order/static/service/bg-popup-phone.png View File

Before After
Width: 684  |  Height: 701  |  Size: 21 KiB

BIN
pages_order/static/service/bg-popup-qr.png View File

Before After
Width: 684  |  Height: 826  |  Size: 23 KiB

BIN
pages_order/static/service/icon-message.png View File

Before After
Width: 66  |  Height: 66  |  Size: 2.4 KiB

BIN
pages_order/static/service/icon-phone.png View File

Before After
Width: 61  |  Height: 61  |  Size: 2.3 KiB

BIN
pages_order/static/service/icon-service.png View File

Before After
Width: 169  |  Height: 194  |  Size: 9.9 KiB

BIN
pages_order/static/service/icon-wx.png View File

Before After
Width: 77  |  Height: 62  |  Size: 3.6 KiB

BIN
pages_order/static/test/bg-test-finsih.png View File

Before After
Width: 684  |  Height: 749  |  Size: 44 KiB

BIN
pages_order/static/test/icon-warning.png View File

Before After
Width: 31  |  Height: 31  |  Size: 1.2 KiB

+ 0
- 428
pages_order/test/answer.vue View File

@ -1,428 +0,0 @@
<template>
<view class="page__view">
<navbar title="答题测评" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
<!-- 答题完成 -->
<template v-if="total && current === total">
<view class="flex main is-finish">
<view class="card">
<image class="card-bg" src="@/pages_order/static/test/bg-test-finsih.png" mode="widthFix"></image>
<view class="flex flex-column card-content">
<view class="text">恭喜你</view>
<view class="text">您已完成所有测评题目</view>
<button class="btn" @click="onCreateReport">生成报告</button>
</view>
</view>
</view>
</template>
<!-- 答题中 -->
<template v-else-if="currentQuestion">
<view class="bar">
<view class="flex info">
<view>答题进度</view>
<view>
<text class="highlight">{{ current + 1 }}</text>
<text>{{ `/${total}` }}</text>
</view>
</view>
<view class="progress">
<view class="progress-bar" :style="{ width: `${progress}%` }"></view>
</view>
</view>
<view class="main">
<view class="card">
<view class="card-header">
<view class="flex tips">
<image class="icon" src="@/pages_order/static/test/icon-warning.png" mode="widthFix"></image>
<view>请根据真实情况谨慎作答点击下一题提交答案无法更改</view>
</view>
<view class="question">{{ currentQuestion.question }}</view>
</view>
<view class="card-content">
<view class="select">
<view
v-for="item in currentQuestion.options"
:key="item.id"
:class="['select-option', item.id === value ? 'is-active' : '']"
@click="onSelect(item.id)"
>
{{ item.content }}
</view>
</view>
</view>
</view>
</view>
<view class="bottom">
<button v-if="isLast" class="btn" @click="finish">提交</button>
<button v-else class="btn" @click="next">下一题</button>
</view>
</template>
</view>
</template>
<script>
export default {
data() {
return {
current: null,
tabs: [],
value: null,
answers: [],
batchNo: null,
questionsList: [],
total: 0,
}
},
computed: {
preIdx() {
let index = this.tabs.findIndex(index => index === this.current)
return index - 1
},
progress() {
return 100 * (this.current + 1) / this.total
},
isLast() {
return this.progress === 100
},
currentQuestion() {
return this.questionsList[this.current]
},
},
onLoad(arg) {
const { ids, examId, current } = arg
this.current = parseInt(current || 0)
this.fetchQuestionList(ids, examId)
this.value = this.answers[this.current]
console.log('currentQuestion', this.currentQuestion)
},
methods: {
async fetchQuestionList(categories, examId) {
let result
if (examId) {
result = await this.$fetch('queryExamById', { examId })
} else {
result = await this.$fetch('queryQuestionList', { categories })
}
const { batchNo, pageList } = result
this.batchNo = batchNo
this.questionsList = pageList.map((item, index) => {
const { id, question, answerList } = item
return {
id,
// question: `${index + 1}${question}`,
question,
options: answerList.map((option, oIdx) => {
return {
id: option.id,
// content: `${String.fromCharCode(oIdx+65)}${option.answer}`
content: `${option.answerNo}${option.answer}`
}
}),
}
})
this.total = this.questionsList.length
this.answers = this.questionsList.map(() => null)
console.log('questionsList', this.questionsList)
console.log('answers', this.answers)
},
async fetchAnswer() {
try {
const { id: questionId } = this.currentQuestion
console.log('currentQuestion', this.currentQuestion)
console.log('value', this.value)
if (!this.value) {
console.log('未答题')
uni.showToast({
title: '请答题',
icon:'none'
})
return false
}
let params = {
batchNo: this.batchNo,
questionId,
answerId: this.value,
}
await this.$fetch('updateAnswer', params)
this.answers[this.current] = this.value
return true
} catch (err) {
console.log('fetchAnswer', err)
return false
}
},
async fetchFinish() {
// todo: delete
// todo
// await this.$fetch('submitPaper', { id: this.paperInfo.reportId })
this.current = this.total
console.log('fetchFinish', this.current, this.currentQuestion)
// todo
// uni.reLaunch({
// url: '/pages/index/report'
// })
},
async next() {
let succ = await this.fetchAnswer()
if (!succ) {
return
}
this.current += 1
this.value = this.answers[this.current]
},
async finish() {
let succ = await this.fetchAnswer()
if (!succ) {
return
}
this.fetchFinish()
},
async onSelect(id) {
this.value = id
},
async onSelectMulitple(id) {
this.value = this.value.includes(id) ? this.value.filter(item => item !== id) : this.value.concat(id)
},
onCreateReport() {
uni.redirectTo({
url: `/pages_order/report/pay?batchNo=${this.batchNo}`
})
},
},
}
</script>
<style scoped lang="scss">
.page__view {
width: 100vw;
min-height: 100vh;
background: linear-gradient(164deg, #014FA2, #014FA2, #2E8AED);
position: relative;
}
.bar {
margin-top: 42rpx;
width: 100%;
padding: 0 47rpx;
box-sizing: border-box;
.info {
justify-content: flex-start;
column-gap: 13rpx;
font-size: 28rpx;
color: #A1D6FF;
.highlight {
color: #FFFFFF;
margin-right: 8rpx;
}
}
.progress {
margin-top: 20rpx;
width: 100%;
height: 16rpx;
background: rgba($color: #FFFFFF, $alpha: 0.35);
border-radius: 8rpx;
&-bar {
height: 100%;
background: #FFFFFF;
border-radius: 8rpx;
}
}
}
.main {
width: 100%;
padding: 73rpx 33rpx;
box-sizing: border-box;
}
.card {
position: relative;
width: 100%;
min-height: 876rpx;
padding: 27rpx 0;
box-sizing: border-box;
background: #FFFFFF;
border-radius: 16rpx;
&:after {
content: ' ';
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 100%);
width: calc(100% - 20rpx * 2);
height: 28rpx;
background: rgba($color: #E9EFF2, $alpha: 0.29);
border-bottom-left-radius: 16rpx;
border-bottom-right-radius: 16rpx;
}
&-header {
padding: 0 33rpx;
.tips {
column-gap: 3rpx;
padding: 12rpx 5rpx;
font-size: 22rpx;
color: #DB5742;
border: 3rpx solid #DB5742;
border-radius: 7rpx;
margin-bottom: 26rpx;
.icon {
width: 31rpx;
height: auto;
}
}
}
&-content {
padding: 0 24rpx;
}
}
.question {
font-family: PingFang SC;
font-weight: 400;
font-size: 28rpx;
line-height: 50rpx;
color: #000000;
margin-bottom: 64rpx;
}
.select {
&-option {
margin-top: 44rpx;
padding: 22rpx 28rpx;
line-height: 1.3;
font-size: 28rpx;
color: #707070;
background: #F3F3F3;
border-radius: 28rpx;
&.is-active {
color: #014FA2;
background: rgba($color: #014FA2, $alpha: 0.22);
}
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 17rpx 72rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 17rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 26rpx 0;
font-size: 30rpx;
line-height: 1.4;
color: #FFFFFF;
background: #014FA2;
border-radius: 42rpx;
}
}
.desc {
margin-top: 220rpx;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.4;
font-size: 26rpx;
color: #989898;
}
.main.is-finish {
height: calc(100vh - (var(--status-bar-height) + 120rpx));
padding: 0 33rpx;
padding-bottom: calc(var(--status-bar-height) + 120rpx);
.card {
min-height: 745rpx;
padding: 0;
background: transparent;
&-bg {
width: 100%;
height: auto;
}
&-content {
position: absolute;
top: 0;
left: 0;
justify-content: flex-end;
width: 100%;
height: 100%;
padding: 69rpx 94rpx;
box-sizing: border-box;
.text {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
.text + .text {
margin-top: 45rpx;
}
.btn {
margin-top: 139rpx;
padding: 29rpx 183rpx;
box-sizing: border-box;
line-height: 1.4;
white-space: nowrap;
color: #FFFFFF;
background: #014FA2;
border-radius: 50rpx;
}
}
}
}
</style>

+ 0
- 51
pages_order/test/list.vue View File

@ -1,51 +0,0 @@
<template>
<view class="page__view">
<navbar title="我的答题" leftClick @leftClick="$utils.navigateBack" />
<view class="list">
<view class="list-item" v-for="item in list" :key="item.id">
<testCard :data="item"></testCard>
</view>
</view>
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import testCard from './testCard.vue'
export default {
mixins: [mixinsList],
components: {
testCard,
},
data() {
return {
list: [],
mixinsListApi: 'queryExamLogList',
}
},
methods: {
},
}
</script>
<style scoped lang="scss">
.page__view {
background: #F5F5F5;
}
.list {
width: 100%;
padding: 29rpx;
box-sizing: border-box;
&-item {
& + & {
margin-top: 20rpx;
}
}
}
</style>

+ 0
- 162
pages_order/test/start.vue View File

@ -1,162 +0,0 @@
<template>
<view class="page__view">
<navbar title="答题测评" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
<view class="main">
<view class="card">
<view class="flex flex-column card-header">
<view>您好 !</view>
<view>请选择您要答题的题库可多选</view>
</view>
<view class="card-content list">
<uv-checkbox-group
v-model="selectedArr"
shape="circle"
>
<view class="flex list-item" v-for="item in list" :key="item.id">
<view class="flex left">
<image class="icon" src="@/static/image/icon.png" mode="widthFix"></image>
<view>{{ item.title }}</view>
</view>
<view>
<uv-checkbox
size="40rpx"
icon-size="40rpx"
activeColor="#014FA2"
:name="item.id"
></uv-checkbox>
</view>
</view>
</uv-checkbox-group>
</view>
</view>
</view>
<view class="bottom">
<button class="btn" @click="onStart">开始答题</button>
</view>
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
export default {
mixins: [mixinsList],
data() {
return {
list: [],
selectedArr: [],
mixinsListApi: 'queryCategoryList',
}
},
computed: {
},
onLoad() {
},
methods: {
onStart() {
if (!this.selectedArr.length) {
uni.showToast({
title: '请选择您要答题的题库(可多选)',
icon:'none'
})
return
}
let ids = this.selectedArr.join(';')
uni.redirectTo({
url: `/pages_order/test/answer?ids=${ids}`
})
},
},
}
</script>
<style scoped lang="scss">
.page__view {
width: 100vw;
min-height: 100vh;
background: linear-gradient(164deg, #014FA2, #014FA2, #2E8AED);
position: relative;
}
.main {
width: 100%;
padding: 54rpx 36rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 152rpx + 73rpx);
box-sizing: border-box;
}
.card {
padding: 34rpx 43rpx 34rpx 19rpx;
background: linear-gradient(rgba($color: #3381D4, $alpha: 0.50), rgba($color: #FCFDFE, $alpha: 0.90) 281rpx, rgba($color: #FCFDFE, $alpha: 0.90));
border-radius: 25rpx;
// border: 3rpx solid #FFFFFF;
box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
&-header {
align-items: flex-start;
row-gap: 10rpx;
padding: 0 0 27rpx 5rpx;
font-size: 30rpx;
line-height: 1.4;
color: #FFFFFF;
}
&-content {
// padding: 0 16rpx;
}
}
.list {
&-item {
width: 100%;
justify-content: space-between;
padding: 30rpx 42rpx 30rpx 24rpx;
box-sizing: border-box;
font-size: 30rpx;
color: #000000;
background: rgba($color: #62BBFF, $alpha: 0.06);
border-radius: 16rpx;
& + & {
margin-top: 17rpx;
}
.left {
column-gap: 18rpx;
}
.icon {
width: 48rpx;
height: auto;
}
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 17rpx 72rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 17rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 26rpx 0;
font-size: 30rpx;
line-height: 1.4;
color: #FFFFFF;
background: #014FA2;
border-radius: 42rpx;
}
}
</style>

+ 0
- 124
pages_order/test/testCard.vue View File

@ -1,124 +0,0 @@
<template>
<view class="card">
<view class="flex card-header">
<!-- todo: 缺切图 -->
<image class="icon" src="@/static/image/icon.png" mode="widthFix"></image>
<view>{{ unfinishCount ? `您还有${unfinishCount}道题未完成` : '您已完成测评,还未获取报告' }}</view>
</view>
<view class="card-content">
<view class="row">
<view class="row-label">答题时间</view>
<view class="row-content">{{ $dayjs(data.createTime).format('YYYY-MM-DD HH:mm') }}</view>
</view>
</view>
<view class="flex card-footer">
<button class="btn" @click="onRestart">重新测评</button>
<button v-if="unfinishCount" class="btn btn-primary" @click="onContinue">继续答题</button>
<button v-else class="btn btn-primary" @click="onCreateReport">获取报告</button>
</view>
</view>
</template>
<script>
export default {
props: {
data: {
type: Object,
default() {
return {}
}
}
},
computed: {
unfinishCount() {
const { allNum, finishNum } = this.data
return allNum - finishNum
},
},
methods: {
onRestart() {
// todo: fetch by this.data.paperId
// let id
// uni.navigateTo({
// url: `/pages_order/test/answer?id=${id}`
// })
uni.navigateTo({
url: `/pages_order/test/start`
})
},
onContinue() {
uni.navigateTo({
url: `/pages_order/test/answer?examId=${this.data.id}`,
})
},
onCreateReport() {
// todo: check
uni.navigateTo({
url: `/pages_order/report/pay?batchNo=${this.data.batchNo}`
})
},
},
}
</script>
<style scoped lang="scss">
.card {
position: relative;
padding: 17rpx 0 22rpx 0;
color: #000000;
background: #FFFFFF;
border-radius: 15rpx;
overflow: hidden;
&-header {
justify-content: flex-start;
column-gap: 24rpx;
padding: 0 26rpx;
font-size: 30rpx;
.icon {
width: 48rpx;
height: auto;
}
}
&-content {
padding-left: 94rpx;
}
&-footer {
padding: 22rpx 35rpx 0 35rpx;
column-gap: 25rpx;
}
}
.row {
margin-top: 12rpx;
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 26rpx;
font-size: 28rpx;
color: #999999;
}
.btn {
flex: 1;
padding: 17rpx 0;
box-sizing: border-box;
font-family: PingFang SC;
font-size: 22rpx;
line-height: 1.4;
color: #014FA2;
border: 3rpx solid #014FA2;
border-radius: 35rpx;
&-primary {
color: #FFFFFF;
background: #014FA2;
}
}
</style>

BIN
static/image/avatar-default.png View File

Before After
Width: 156  |  Height: 156  |  Size: 7.8 KiB

BIN
static/image/icon-center-feedback.png View File

Before After
Width: 51  |  Height: 51  |  Size: 2.5 KiB

BIN
static/image/icon-center-logout.png View File

Before After
Width: 51  |  Height: 51  |  Size: 1.4 KiB

BIN
static/image/icon-center-service.png View File

Before After
Width: 51  |  Height: 51  |  Size: 2.5 KiB

BIN
static/image/icon-center-test.png View File

Before After
Width: 51  |  Height: 51  |  Size: 1.6 KiB

BIN
static/image/icon-center-userinfo.png View File

Before After
Width: 51  |  Height: 51  |  Size: 2.0 KiB

BIN
static/image/icon-index.png View File

Before After
Width: 286  |  Height: 297  |  Size: 25 KiB

BIN
static/image/icon-unfinish.png View File

Before After
Width: 100  |  Height: 90  |  Size: 3.4 KiB

BIN
static/image/icon.png View File

Before After
Width: 48  |  Height: 48  |  Size: 2.1 KiB

BIN
static/image/tabbar/home-active.png View File

Before After
Width: 72  |  Height: 72  |  Size: 2.9 KiB

BIN
static/image/tabbar/home.png View File

Before After
Width: 72  |  Height: 72  |  Size: 2.5 KiB

BIN
static/image/tabbar/report-active.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.5 KiB

BIN
static/image/tabbar/report.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.4 KiB

BIN
static/image/tabbar/user-center-active.png View File

Before After
Width: 72  |  Height: 72  |  Size: 3.5 KiB

BIN
static/image/tabbar/user-center.png View File

Before After
Width: 72  |  Height: 72  |  Size: 3.0 KiB

+ 1
- 0
uni.webview.1.5.6.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save