Merge remote-tracking branch 'origin/master'
Showing
9 changed files
with
333 additions
and
58 deletions
CLAUDE.md
0 → 100644
| 1 | # CLAUDE.md | ||
| 2 | |||
| 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
| 4 | |||
| 5 | ## Project Overview | ||
| 6 | |||
| 7 | This is a **uni-app** (Vue 3) WeChat mini-program project for the **China Taekwondo Association (中国跆拳道协会)** membership management system. | ||
| 8 | |||
| 9 | - **Platform**: mp-weixin (WeChat Mini-Program) | ||
| 10 | - **Vue Version**: Vue 3 with `<script setup>` syntax | ||
| 11 | - **State Management**: Pinia | ||
| 12 | - **UI Framework**: uni-ui (components in `uni_modules/`) | ||
| 13 | - **Key Dependencies**: dayjs, underscore, lodash, crypto-js | ||
| 14 | |||
| 15 | ## Development Commands | ||
| 16 | |||
| 17 | ### Running the Project | ||
| 18 | - Use **HBuilderX** to open this project | ||
| 19 | - Or use CLI: `npm run dev:mp-weixin` | ||
| 20 | - Build: `npm run build:mp-weixin` | ||
| 21 | |||
| 22 | ### Key Configurations | ||
| 23 | - `config.js` - API base URLs (dev/prod switching) | ||
| 24 | - `pages.json` - Page routing and global settings | ||
| 25 | - `manifest.json` - App configuration (appid, platform settings) | ||
| 26 | |||
| 27 | ## Architecture | ||
| 28 | |||
| 29 | ### Directory Structure | ||
| 30 | ``` | ||
| 31 | ├── common/ # Shared utilities | ||
| 32 | │ ├── api.js # API functions (imported as @/common/api.js) | ||
| 33 | │ ├── request.js # HTTP request wrapper | ||
| 34 | │ ├── login.js # Login logic | ||
| 35 | │ ├── utils.js # Utility functions | ||
| 36 | │ └── pay.js # Payment logic | ||
| 37 | ├── config.js # Environment config (API endpoints) | ||
| 38 | ├── pages/ # Main package pages (index, exam, invoice, rank, webview) | ||
| 39 | ├── login/ # Login sub-package | ||
| 40 | ├── personal/ # Personal member sub-package | ||
| 41 | ├── personalVip/ # VIP member sub-package | ||
| 42 | ├── group/ # Group/Organization sub-package | ||
| 43 | ├── level/ # Level examination sub-package | ||
| 44 | ├── myCenter/ # User center sub-package | ||
| 45 | ├── uni_modules/ # uni-ui components | ||
| 46 | └── static/ # Static assets | ||
| 47 | ``` | ||
| 48 | |||
| 49 | ### API Pattern | ||
| 50 | All API functions are defined in `common/api.js` using a consistent pattern: | ||
| 51 | ```js | ||
| 52 | export function apiFunctionName(data) { | ||
| 53 | return request({ | ||
| 54 | url: '/path/to/endpoint', | ||
| 55 | method: 'post', // or 'get', 'put', 'delete' | ||
| 56 | params: data | ||
| 57 | }) | ||
| 58 | } | ||
| 59 | ``` | ||
| 60 | |||
| 61 | ### Page Sub-packages | ||
| 62 | Pages are organized into sub-packages defined in `pages.json` to optimize loading. Each sub-package has its own root directory (e.g., `level/`, `myCenter/`). | ||
| 63 | |||
| 64 | ### Component Auto-import | ||
| 65 | uni-ui components are auto-imported via easycom in `pages.json`: | ||
| 66 | ```json | ||
| 67 | "easycom": { | ||
| 68 | "autoscan": true, | ||
| 69 | "custom": { | ||
| 70 | "^uni-(.*)": "uni_modules/uni-$1/components/uni-$1/uni-$1.vue" | ||
| 71 | } | ||
| 72 | } | ||
| 73 | ``` | ||
| 74 | |||
| 75 | ### Global Data | ||
| 76 | `app.globalData` contains shared state (from `App.vue`): | ||
| 77 | - `memberInfo` - Current member info | ||
| 78 | - `isLogin` - Login status | ||
| 79 | - `deptType` - Department type | ||
| 80 | |||
| 81 | Access via: `const app = getApp(); app.globalData.memberInfo` | ||
| 82 | |||
| 83 | ### Form Handling Pattern | ||
| 84 | For forms with `uni-forms`, use `Object.assign(form.value, data)` instead of `form.value = data` to preserve reactive bindings. | ||
| 85 | |||
| 86 | ### DateTime Picker | ||
| 87 | `uni-datetime-picker` requires ISO format strings or timestamps for v-model values. | ||
| 88 | |||
| 89 | ### File Upload Pattern | ||
| 90 | Use `api.uploadFile(e)` or `api.uploadImg(e)` from `common/api.js` which return `{ code, msg }` - the file URL is in `res.msg`. | ||
| 91 | |||
| 92 | ## Common Issues | ||
| 93 | |||
| 94 | ### uni-data-select not working | ||
| 95 | If `uni-data-select` dropdowns don't appear, ensure: | ||
| 96 | 1. easycom is properly configured in `pages.json` | ||
| 97 | 2. The component is not blocked by CSS `overflow: hidden` on parent containers | ||
| 98 | |||
| 99 | ### Responsive Data Binding | ||
| 100 | When updating form data from API responses, use `Object.assign()` to maintain Vue 3 reactivity: | ||
| 101 | ```js | ||
| 102 | // Instead of: form.value = res.data | ||
| 103 | Object.assign(form.value, res.data) | ||
| 104 | ``` |
| ... | @@ -61,7 +61,14 @@ function getCodeImg() { | ... | @@ -61,7 +61,14 @@ function getCodeImg() { |
| 61 | method: 'get' | 61 | method: 'get' |
| 62 | }) | 62 | }) |
| 63 | } | 63 | } |
| 64 | 64 | function getSmsCodeImg(data) { | |
| 65 | return request({ | ||
| 66 | url: '/captchaSmsWithCaptchaImage', | ||
| 67 | // url: '/captchaSmsWithCaptchaImageForMiniApp', | ||
| 68 | method: 'post', | ||
| 69 | params: data | ||
| 70 | }) | ||
| 71 | } | ||
| 65 | // 代退图形认证的获取手机验证码 | 72 | // 代退图形认证的获取手机验证码 |
| 66 | function getSmsCode(data) { | 73 | function getSmsCode(data) { |
| 67 | return request({ | 74 | return request({ |
| ... | @@ -241,6 +248,7 @@ export { | ... | @@ -241,6 +248,7 @@ export { |
| 241 | pcLogin, | 248 | pcLogin, |
| 242 | getCodeImg, | 249 | getCodeImg, |
| 243 | getSmsCode, | 250 | getSmsCode, |
| 251 | getSmsCodeImg, | ||
| 244 | h5Login, | 252 | h5Login, |
| 245 | h5LoginAuto, | 253 | h5LoginAuto, |
| 246 | loginByPhone, | 254 | loginByPhone, | ... | ... |
| ... | @@ -4,13 +4,13 @@ page { | ... | @@ -4,13 +4,13 @@ page { |
| 4 | background: #ecf0f6; | 4 | background: #ecf0f6; |
| 5 | } | 5 | } |
| 6 | /* uni-data-checkbox 选中色全局覆盖为红色 */ | 6 | /* uni-data-checkbox 选中色全局覆盖为红色 */ |
| 7 | uni-data-checkbox .checklist-box.is-checked { | 7 | // uni-data-checkbox .checklist-box.is-checked { |
| 8 | border-color: #C4121B !important; | 8 | // border-color: #C4121B !important; |
| 9 | background-color: #C4121B !important; | 9 | // background-color: #C4121B !important; |
| 10 | } | 10 | // } |
| 11 | uni-data-checkbox .checklist-box.is-checked .checklist-text { | 11 | // uni-data-checkbox .checklist-box.is-checked .checklist-text { |
| 12 | color: #fff !important; | 12 | // color: #fff !important; |
| 13 | } | 13 | // } |
| 14 | .wBox{box-sizing: border-box;} | 14 | .wBox{box-sizing: border-box;} |
| 15 | .h3 {font-weight: bold;line-height: 2;} | 15 | .h3 {font-weight: bold;line-height: 2;} |
| 16 | .text-center{text-align: center;} | 16 | .text-center{text-align: center;} | ... | ... |
| ... | @@ -933,7 +933,7 @@ | ... | @@ -933,7 +933,7 @@ |
| 933 | padding: 20rpx 0; | 933 | padding: 20rpx 0; |
| 934 | background: #fff; | 934 | background: #fff; |
| 935 | border-top: 1rpx solid #f0f0f0; | 935 | border-top: 1rpx solid #f0f0f0; |
| 936 | z-index: 999; | 936 | z-index: 98; |
| 937 | 937 | ||
| 938 | .btn-red { | 938 | .btn-red { |
| 939 | background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%); | 939 | background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%); | ... | ... |
| ... | @@ -68,7 +68,7 @@ import { | ... | @@ -68,7 +68,7 @@ import { |
| 68 | } from 'vue' | 68 | } from 'vue' |
| 69 | import { | 69 | import { |
| 70 | getCodeImg, | 70 | getCodeImg, |
| 71 | getSmsCode, | 71 | getSmsCodeImg, |
| 72 | groupMemberRegister | 72 | groupMemberRegister |
| 73 | } from '@/common/login.js' | 73 | } from '@/common/login.js' |
| 74 | import config from '@/config.js' | 74 | import config from '@/config.js' |
| ... | @@ -113,6 +113,14 @@ function register() { | ... | @@ -113,6 +113,14 @@ function register() { |
| 113 | }) | 113 | }) |
| 114 | return | 114 | return |
| 115 | } | 115 | } |
| 116 | // 密码强度校验:8~18位大小写字母加数字加特殊符号组合 | ||
| 117 | if (!validPassword(registerForm.value.password)) { | ||
| 118 | uni.showToast({ | ||
| 119 | title: '密码必须为8~18位大小写字母、数字和特殊符号组合', | ||
| 120 | icon: 'none' | ||
| 121 | }) | ||
| 122 | return | ||
| 123 | } | ||
| 116 | if (registerForm.value.password != registerForm.value.password2) { | 124 | if (registerForm.value.password != registerForm.value.password2) { |
| 117 | uni.showToast({ | 125 | uni.showToast({ |
| 118 | title: '两次密码不一致,请重新输入', | 126 | title: '两次密码不一致,请重新输入', |
| ... | @@ -131,13 +139,27 @@ function register() { | ... | @@ -131,13 +139,27 @@ function register() { |
| 131 | groupMemberRegister(registerForm.value) | 139 | groupMemberRegister(registerForm.value) |
| 132 | .then((res) => { | 140 | .then((res) => { |
| 133 | uni.showToast({ | 141 | uni.showToast({ |
| 134 | title: `恭喜你,您的账号 ${registerForm.value.telNo} 注册成功!` | 142 | title: `恭喜你,您的账号 ${registerForm.value.telNo} 注册成功!`, |
| 143 | icon: 'none' | ||
| 135 | }) | 144 | }) |
| 136 | registerForm.value = {} | 145 | registerForm.value = {} |
| 137 | setTimeout(goLogin, 2000) | 146 | setTimeout(goLogin, 2000) |
| 138 | }) | 147 | }) |
| 139 | } | 148 | } |
| 140 | 149 | ||
| 150 | // 密码校验:8~18位大小写字母加数字加特殊符号组合 | ||
| 151 | function validPassword(pwd) { | ||
| 152 | if (!pwd || pwd.length < 8 || pwd.length > 18) { | ||
| 153 | return false | ||
| 154 | } | ||
| 155 | const lowerRegex = /[a-z]+/ | ||
| 156 | const upperRegex = /[A-Z]+/ | ||
| 157 | const digitRegex = /[0-9]+/ | ||
| 158 | const symbolRegex = /[\W_]+/ | ||
| 159 | const specific = /.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/].*/ | ||
| 160 | return (lowerRegex.test(pwd) && upperRegex.test(pwd) && digitRegex.test(pwd) && symbolRegex.test(pwd) && specific.test(pwd)) | ||
| 161 | } | ||
| 162 | |||
| 141 | function goLogin() { | 163 | function goLogin() { |
| 142 | let path = '/login/loginC'; | 164 | let path = '/login/loginC'; |
| 143 | uni.navigateTo({ | 165 | uni.navigateTo({ |
| ... | @@ -169,7 +191,7 @@ function getCaptchaSms() { | ... | @@ -169,7 +191,7 @@ function getCaptchaSms() { |
| 169 | return | 191 | return |
| 170 | } | 192 | } |
| 171 | 193 | ||
| 172 | getSmsCode({ | 194 | getSmsCodeImg({ |
| 173 | uuid: registerForm.value.uuid, | 195 | uuid: registerForm.value.uuid, |
| 174 | telNo: registerForm.value.telNo, | 196 | telNo: registerForm.value.telNo, |
| 175 | code: registerForm.value.captcha | 197 | code: registerForm.value.captcha | ... | ... |
| ... | @@ -264,10 +264,10 @@ | ... | @@ -264,10 +264,10 @@ |
| 264 | getTree() | 264 | getTree() |
| 265 | form.value.deptType = res.data.dept.deptType | 265 | form.value.deptType = res.data.dept.deptType |
| 266 | form.value.parentId = form.value.parentId.toString() | 266 | form.value.parentId = form.value.parentId.toString() |
| 267 | creditCode.value = form.value.creditCode | 267 | // creditCode.value = form.value.creditCode |
| 268 | companyName.value = form.value.companyName | 268 | // form.value.companyName = res.data.memberInfo.companyName |
| 269 | belongProvinceId.value = form.value.belongProvinceId | 269 | // belongProvinceId.value = form.value.belongProvinceId |
| 270 | parentId.value = form.value.parentId | 270 | // parentId.value = form.value.parentId |
| 271 | 271 | ||
| 272 | if (form.value.regionId) { | 272 | if (form.value.regionId) { |
| 273 | form.value.coordinates1 = form.value.regionId | 273 | form.value.coordinates1 = form.value.regionId | ... | ... |
| ... | @@ -22,7 +22,9 @@ | ... | @@ -22,7 +22,9 @@ |
| 22 | <uni-easyinput class="input-with-border" v-model="form.baseName" :disabled="!editIng" placeholder="单位名称" /> | 22 | <uni-easyinput class="input-with-border" v-model="form.baseName" :disabled="!editIng" placeholder="单位名称" /> |
| 23 | </uni-forms-item> | 23 | </uni-forms-item> |
| 24 | <uni-forms-item label="单位类型" required> | 24 | <uni-forms-item label="单位类型" required> |
| 25 | <uni-data-select :disabled="!editIng" v-model="form.type" :localdata="typeList"></uni-data-select> | 25 | <view style="width: 100%;"> |
| 26 | <uni-data-select v-model="form.type" :localdata="typeList" placeholder="请选择单位类型"></uni-data-select> | ||
| 27 | </view> | ||
| 26 | </uni-forms-item> | 28 | </uni-forms-item> |
| 27 | <uni-forms-item label="联系人" required> | 29 | <uni-forms-item label="联系人" required> |
| 28 | <uni-easyinput class="input-with-border" v-model="form.contact" :disabled="!editIng" placeholder="请输入联系人姓名" /> | 30 | <uni-easyinput class="input-with-border" v-model="form.contact" :disabled="!editIng" placeholder="请输入联系人姓名" /> |
| ... | @@ -51,10 +53,10 @@ | ... | @@ -51,10 +53,10 @@ |
| 51 | <text v-if="authenticationStatusa == 4" class="text-warning">即将过期</text> | 53 | <text v-if="authenticationStatusa == 4" class="text-warning">即将过期</text> |
| 52 | <text v-if="authenticationStatusa == 5" class="text-danger">已过期</text> | 54 | <text v-if="authenticationStatusa == 5" class="text-danger">已过期</text> |
| 53 | </view> | 55 | </view> |
| 54 | <view class="btn-row"> | 56 | <!-- <view class="btn-row"> |
| 55 | <button type="primary" :disabled="btn" @click="goPay">去缴费</button> | 57 | <button type="primary" :disabled="btn" @click="goPay">去缴费</button> |
| 56 | <button v-if="form.deptType != 2" type="default" @click="goAuditDetail">审核详情</button> | 58 | <button v-if="form.deptType != 2" type="default" @click="goAuditDetail">审核详情</button> |
| 57 | </view> | 59 | </view> --> |
| 58 | </view> | 60 | </view> |
| 59 | 61 | ||
| 60 | <uni-forms ref="certForm" :modelValue="form" label-width="90"> | 62 | <uni-forms ref="certForm" :modelValue="form" label-width="90"> |
| ... | @@ -100,7 +102,7 @@ | ... | @@ -100,7 +102,7 @@ |
| 100 | <image :src="config.baseUrl_api + '/fs/static/yyzz@2x.png'" class="placeholder-img"/> | 102 | <image :src="config.baseUrl_api + '/fs/static/yyzz@2x.png'" class="placeholder-img"/> |
| 101 | </view> | 103 | </view> |
| 102 | <view v-else class="license-preview"> | 104 | <view v-else class="license-preview"> |
| 103 | <image v-if="typeof form.businessLicense === 'string'" :src="form.businessLicense" class="license-img" @click="previewImage(form.businessLicense)"></image> | 105 | <image :src="getImageUrl(getBusinessLicenseUrl())" class="license-img" @click="previewImage(getImageUrl(getBusinessLicenseUrl()))"></image> |
| 104 | <view class="delete-btn" v-if="editIng" @click="removeBusinessLicense">×</view> | 106 | <view class="delete-btn" v-if="editIng" @click="removeBusinessLicense">×</view> |
| 105 | </view> | 107 | </view> |
| 106 | </view> | 108 | </view> |
| ... | @@ -118,7 +120,7 @@ | ... | @@ -118,7 +120,7 @@ |
| 118 | <image :src="config.baseUrl_api + '/fs/static/sfz_zm@2x.png'" class="placeholder-img"/> | 120 | <image :src="config.baseUrl_api + '/fs/static/sfz_zm@2x.png'" class="placeholder-img"/> |
| 119 | </view> | 121 | </view> |
| 120 | <view v-else class="idcard-preview"> | 122 | <view v-else class="idcard-preview"> |
| 121 | <image :src="form.legalIdcPhoto1" class="idcard-img" @click="previewImage(form.legalIdcPhoto1)"></image> | 123 | <image :src="getImageUrl(form.legalIdcPhoto1)" class="idcard-img" @click="previewImage(getImageUrl(form.legalIdcPhoto1))"></image> |
| 122 | <view class="delete-btn" v-if="editIng" @click="removeIdCardFront">×</view> | 124 | <view class="delete-btn" v-if="editIng" @click="removeIdCardFront">×</view> |
| 123 | </view> | 125 | </view> |
| 124 | </view> | 126 | </view> |
| ... | @@ -129,7 +131,7 @@ | ... | @@ -129,7 +131,7 @@ |
| 129 | <image :src="config.baseUrl_api + '/fs/static/sfz_fm@2x.png'" class="placeholder-img"/> | 131 | <image :src="config.baseUrl_api + '/fs/static/sfz_fm@2x.png'" class="placeholder-img"/> |
| 130 | </view> | 132 | </view> |
| 131 | <view v-else class="idcard-preview"> | 133 | <view v-else class="idcard-preview"> |
| 132 | <image :src="form.legalIdcPhoto2" class="idcard-img" @click="previewImage(form.legalIdcPhoto2)"></image> | 134 | <image :src="getImageUrl(form.legalIdcPhoto2)" class="idcard-img" @click="previewImage(getImageUrl(form.legalIdcPhoto2))"></image> |
| 133 | <view class="delete-btn" v-if="editIng" @click="removeIdCardBack">×</view> | 135 | <view class="delete-btn" v-if="editIng" @click="removeIdCardBack">×</view> |
| 134 | </view> | 136 | </view> |
| 135 | </view> | 137 | </view> |
| ... | @@ -147,7 +149,7 @@ | ... | @@ -147,7 +149,7 @@ |
| 147 | <image :src="config.baseUrl_api + '/fs/static/jgzp@2x.png'" class="placeholder-img"/> | 149 | <image :src="config.baseUrl_api + '/fs/static/jgzp@2x.png'" class="placeholder-img"/> |
| 148 | </view> | 150 | </view> |
| 149 | <view v-else class="pictures-preview"> | 151 | <view v-else class="pictures-preview"> |
| 150 | <image :src="form.pictures.split(',')[0]" class="picture-img" @click="previewImage(form.pictures.split(','))"></image> | 152 | <image :src="getImageUrl(form.pictures.split(',')[0])" class="picture-img" @click="previewImage(form.pictures.split(',').map(url => getImageUrl(url)))"></image> |
| 151 | <view class="delete-btn" v-if="editIng" @click="removePictures">×</view> | 153 | <view class="delete-btn" v-if="editIng" @click="removePictures">×</view> |
| 152 | </view> | 154 | </view> |
| 153 | </view> | 155 | </view> |
| ... | @@ -166,7 +168,8 @@ | ... | @@ -166,7 +168,8 @@ |
| 166 | <script setup> | 168 | <script setup> |
| 167 | import { | 169 | import { |
| 168 | ref, | 170 | ref, |
| 169 | reactive | 171 | reactive, |
| 172 | computed | ||
| 170 | } from 'vue'; | 173 | } from 'vue'; |
| 171 | import * as api from '@/common/api.js'; | 174 | import * as api from '@/common/api.js'; |
| 172 | import { | 175 | import { |
| ... | @@ -174,6 +177,7 @@ | ... | @@ -174,6 +177,7 @@ |
| 174 | onShow | 177 | onShow |
| 175 | } from '@dcloudio/uni-app'; | 178 | } from '@dcloudio/uni-app'; |
| 176 | import config from '@/config.js' | 179 | import config from '@/config.js' |
| 180 | // import uniDataSelect from '@/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue' | ||
| 177 | const app = getApp(); | 181 | const app = getApp(); |
| 178 | 182 | ||
| 179 | const form = ref({ | 183 | const form = ref({ |
| ... | @@ -195,6 +199,17 @@ | ... | @@ -195,6 +199,17 @@ |
| 195 | text: '其他' | 199 | text: '其他' |
| 196 | }]) | 200 | }]) |
| 197 | 201 | ||
| 202 | // 类型索引 | ||
| 203 | const typeIndex = computed(() => { | ||
| 204 | return typeList.value.findIndex(item => String(item.value) === String(form.value.type)) | ||
| 205 | }) | ||
| 206 | |||
| 207 | // 类型选择 | ||
| 208 | function typeChange(e) { | ||
| 209 | const index = e.detail.value | ||
| 210 | form.value.type = typeList.value[index].value | ||
| 211 | } | ||
| 212 | |||
| 198 | // 地址选项 | 213 | // 地址选项 |
| 199 | const options = ref([]) | 214 | const options = ref([]) |
| 200 | const regionOptions = ref([]) | 215 | const regionOptions = ref([]) |
| ... | @@ -210,7 +225,7 @@ | ... | @@ -210,7 +225,7 @@ |
| 210 | }, { | 225 | }, { |
| 211 | title: '会员认证' | 226 | title: '会员认证' |
| 212 | }]) | 227 | }]) |
| 213 | 228 | const creditCode = ref('') | |
| 214 | // 编辑状态 | 229 | // 编辑状态 |
| 215 | const editIng = ref(true); | 230 | const editIng = ref(true); |
| 216 | 231 | ||
| ... | @@ -232,6 +247,28 @@ | ... | @@ -232,6 +247,28 @@ |
| 232 | // 考点审核状态 | 247 | // 考点审核状态 |
| 233 | const auditStatus = ref('0') | 248 | const auditStatus = ref('0') |
| 234 | 249 | ||
| 250 | // 图片URL处理:如果不是http开头,拼接baseUrl_api | ||
| 251 | function getImageUrl(url) { | ||
| 252 | if (!url) return '' | ||
| 253 | if (url.indexOf('http') === 0) return url | ||
| 254 | return config.baseUrl_api + url | ||
| 255 | } | ||
| 256 | |||
| 257 | // 解析营业执照URL | ||
| 258 | function getBusinessLicenseUrl() { | ||
| 259 | if (!form.value.businessLicense) return '' | ||
| 260 | try { | ||
| 261 | const arr = JSON.parse(form.value.businessLicense) | ||
| 262 | if (Array.isArray(arr) && arr.length > 0) { | ||
| 263 | return arr[0].url || '' | ||
| 264 | } | ||
| 265 | } catch (e) { | ||
| 266 | // 如果不是JSON格式,可能是直接返回的URL | ||
| 267 | return form.value.businessLicense | ||
| 268 | } | ||
| 269 | return '' | ||
| 270 | } | ||
| 271 | |||
| 235 | onLoad(option => { | 272 | onLoad(option => { |
| 236 | getTree() | 273 | getTree() |
| 237 | if (app.globalData.isLogin) { | 274 | if (app.globalData.isLogin) { |
| ... | @@ -260,6 +297,9 @@ | ... | @@ -260,6 +297,9 @@ |
| 260 | // Object.assign(form.value, res.data.memberInfo) | 297 | // Object.assign(form.value, res.data.memberInfo) |
| 261 | // } | 298 | // } |
| 262 | form.value = { ...res.data.dept, ...res.data.memberInfo } | 299 | form.value = { ...res.data.dept, ...res.data.memberInfo } |
| 300 | if (form.value.type) { | ||
| 301 | form.value.type = String(form.value.type) | ||
| 302 | } | ||
| 263 | authenticationStatusa.value = res.data.authenticationStatus | 303 | authenticationStatusa.value = res.data.authenticationStatus |
| 264 | result.value = res.data.result | 304 | result.value = res.data.result |
| 265 | 305 | ||
| ... | @@ -311,11 +351,11 @@ | ... | @@ -311,11 +351,11 @@ |
| 311 | btn.value = !result.value | 351 | btn.value = !result.value |
| 312 | } | 352 | } |
| 313 | 353 | ||
| 314 | creditCode.value = form.value.creditCode | 354 | // creditCode.value = form.value.creditCode |
| 315 | legal.value = form.value.legal | 355 | // legal.value = form.value.legal |
| 316 | legalIdcCode.value = form.value.legalIdcCode | 356 | // legalIdcCode.value = form.value.legalIdcCode |
| 317 | coordinates1.value = form.value.provinceId | 357 | // coordinates1.value = form.value.provinceId |
| 318 | adress.value = form.value.adress | 358 | // adress.value = form.value.adress |
| 319 | form.value.name = form.value.baseName | 359 | form.value.name = form.value.baseName |
| 320 | }) | 360 | }) |
| 321 | } | 361 | } |
| ... | @@ -601,22 +641,18 @@ | ... | @@ -601,22 +641,18 @@ |
| 601 | 641 | ||
| 602 | // 提交认证信息(100%对齐PC端入参格式) | 642 | // 提交认证信息(100%对齐PC端入参格式) |
| 603 | function submitCertification() { | 643 | function submitCertification() { |
| 604 | uni.showLoading({ title: '提交中...' }) | 644 | let params = { |
| 605 | api.editMyMemberCertifiedInfo({ | ||
| 606 | parentId: form.value.parentId, | 645 | parentId: form.value.parentId, |
| 607 | creditCode: form.value.creditCode, | 646 | creditCode: form.value.creditCode, |
| 608 | legal: form.value.legal, | 647 | legal: form.value.legal, |
| 609 | businessLicense: JSON.stringify({ | 648 | businessLicense: form.value.businessLicense, |
| 610 | url: form.value.businessLicense, | ||
| 611 | name: form.value.businessLicenseName | ||
| 612 | }), | ||
| 613 | pictures: form.value.pictures, | 649 | pictures: form.value.pictures, |
| 614 | memId: form.value.memId, | 650 | memId: form.value.memId, |
| 615 | id: form.value.deptId, | 651 | id: form.value.deptId, |
| 616 | name: form.value.name, | 652 | name: form.value.name, |
| 617 | regionId: form.value.regionId?.value, | 653 | regionId: form.value.regionId?.value, |
| 618 | cityId: form.value.cityId.value, | 654 | cityId: form.value.cityId.value.toString(), |
| 619 | provinceId: form.value.provinceId.value, | 655 | provinceId: form.value.provinceId.value.toString(), |
| 620 | adress: form.value.adress, | 656 | adress: form.value.adress, |
| 621 | deptType: app.globalData.deptType, | 657 | deptType: app.globalData.deptType, |
| 622 | legalIdcPhoto: [form.value.legalIdcPhoto1, form.value.legalIdcPhoto2].join(','), | 658 | legalIdcPhoto: [form.value.legalIdcPhoto1, form.value.legalIdcPhoto2].join(','), |
| ... | @@ -625,7 +661,11 @@ | ... | @@ -625,7 +661,11 @@ |
| 625 | siteTel: form.value.siteTel, | 661 | siteTel: form.value.siteTel, |
| 626 | companyName: form.value.companyName, | 662 | companyName: form.value.companyName, |
| 627 | legalIdcCode: form.value.legalIdcCode | 663 | legalIdcCode: form.value.legalIdcCode |
| 628 | }).then(res => { | 664 | } |
| 665 | console.log(666,params) | ||
| 666 | // return | ||
| 667 | uni.showLoading({ title: '提交中...' }) | ||
| 668 | api.editMyMemberCertifiedInfo(params).then(res => { | ||
| 629 | uni.hideLoading() | 669 | uni.hideLoading() |
| 630 | if (res.code === 200) { | 670 | if (res.code === 200) { |
| 631 | uni.showToast({ title: '提交成功', duration: 1500, icon: 'success' }) | 671 | uni.showToast({ title: '提交成功', duration: 1500, icon: 'success' }) |
| ... | @@ -654,23 +694,41 @@ | ... | @@ -654,23 +694,41 @@ |
| 654 | sourceType: ['album', 'camera'], | 694 | sourceType: ['album', 'camera'], |
| 655 | success: (res) => { | 695 | success: (res) => { |
| 656 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { | 696 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { |
| 657 | form.value.businessLicense = res.tempFilePaths[0] | 697 | uni.showLoading({ title: '上传中...' }) |
| 658 | // 调用API识别营业执照 | 698 | // 先上传文件 |
| 659 | uni.uploadFile({ | 699 | api.uploadFile(res).then(uploadRes => { |
| 700 | if (uploadRes.code !== 200) { | ||
| 701 | throw new Error('上传失败') | ||
| 702 | } | ||
| 703 | const url = uploadRes.msg | ||
| 704 | // 上传成功后调用OCR识别 | ||
| 705 | return uni.uploadFile({ | ||
| 660 | url: config.baseUrl_api + '/member/info/getBusinessLicense', | 706 | url: config.baseUrl_api + '/member/info/getBusinessLicense', |
| 661 | filePath: res.tempFilePaths[0], | 707 | filePath: res.tempFilePaths[0], |
| 662 | name: 'pic', | 708 | name: 'pic', |
| 663 | header: { | 709 | header: { |
| 664 | 'Authorization': uni.getStorageSync('token') | 710 | 'Authorization': uni.getStorageSync('token') |
| 665 | }, | 711 | } |
| 666 | success: (uploadRes) => { | 712 | }).then(ocrRes => { |
| 667 | const data = JSON.parse(uploadRes.data) | 713 | return { url, ocrRes } |
| 714 | }) | ||
| 715 | }).then(({ url, ocrRes }) => { | ||
| 716 | uni.hideLoading() | ||
| 717 | const data = JSON.parse(ocrRes.data) | ||
| 718 | let name = '营业执照' | ||
| 668 | if (data.code === 200 && data.data) { | 719 | if (data.code === 200 && data.data) { |
| 669 | form.value.creditCode = data.data.creditCode | 720 | form.value.creditCode = data.data.creditCode |
| 670 | form.value.companyName = data.data.companyName | 721 | form.value.companyName = data.data.companyName |
| 671 | form.value.businessLicenseName = data.data.name | 722 | name = data.data.name || '营业执照' |
| 672 | } | ||
| 673 | } | 723 | } |
| 724 | // 存储为数组格式的JSON字符串 | ||
| 725 | form.value.businessLicense = JSON.stringify([{ | ||
| 726 | url: url, | ||
| 727 | name: name | ||
| 728 | }]) | ||
| 729 | }).catch(() => { | ||
| 730 | uni.hideLoading() | ||
| 731 | uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 674 | }) | 732 | }) |
| 675 | } | 733 | } |
| 676 | } | 734 | } |
| ... | @@ -692,7 +750,7 @@ | ... | @@ -692,7 +750,7 @@ |
| 692 | form.value.legalIdcPhoto2 = '' | 750 | form.value.legalIdcPhoto2 = '' |
| 693 | } | 751 | } |
| 694 | 752 | ||
| 695 | // 身份证上传(修复:正面调用OCR,和PC端逻辑一致) | 753 | // 身份证上传 |
| 696 | function onIdCardFrontSelect() { | 754 | function onIdCardFrontSelect() { |
| 697 | uni.chooseImage({ | 755 | uni.chooseImage({ |
| 698 | count: 1, | 756 | count: 1, |
| ... | @@ -700,8 +758,16 @@ | ... | @@ -700,8 +758,16 @@ |
| 700 | sourceType: ['album', 'camera'], | 758 | sourceType: ['album', 'camera'], |
| 701 | success: (res) => { | 759 | success: (res) => { |
| 702 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { | 760 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { |
| 703 | form.value.legalIdcPhoto1 = res.tempFilePaths[0] | 761 | uni.showLoading({ title: '上传中...' }) |
| 704 | 762 | api.uploadImg(res).then(data => { | |
| 763 | if (data.code === 200) { | ||
| 764 | form.value.legalIdcPhoto1 = data.msg | ||
| 765 | } | ||
| 766 | uni.hideLoading() | ||
| 767 | }).catch(() => { | ||
| 768 | uni.hideLoading() | ||
| 769 | uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 770 | }) | ||
| 705 | } | 771 | } |
| 706 | } | 772 | } |
| 707 | }) | 773 | }) |
| ... | @@ -714,19 +780,30 @@ | ... | @@ -714,19 +780,30 @@ |
| 714 | sourceType: ['album', 'camera'], | 780 | sourceType: ['album', 'camera'], |
| 715 | success: (res) => { | 781 | success: (res) => { |
| 716 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { | 782 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { |
| 717 | form.value.legalIdcPhoto2 = res.tempFilePaths[0] | 783 | const tempPath = res.tempFilePaths[0] |
| 718 | extractIdCardInfo() // 修复:正面上传后调用OCR提取信息 | 784 | uni.showLoading({ title: '上传中...' }) |
| 785 | api.uploadImg(res).then(data => { | ||
| 786 | if (data.code === 200) { | ||
| 787 | form.value.legalIdcPhoto2 = data.msg | ||
| 788 | // 用临时文件路径调用OCR | ||
| 789 | extractIdCardInfo(tempPath) | ||
| 790 | } | ||
| 791 | uni.hideLoading() | ||
| 792 | }).catch(() => { | ||
| 793 | uni.hideLoading() | ||
| 794 | uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 795 | }) | ||
| 719 | } | 796 | } |
| 720 | } | 797 | } |
| 721 | }) | 798 | }) |
| 722 | } | 799 | } |
| 723 | 800 | ||
| 724 | // 提取身份证信息(修复:传正面照片legalIdcPhoto1,和PC端逻辑一致) | 801 | // 提取身份证信息 |
| 725 | function extractIdCardInfo() { | 802 | function extractIdCardInfo(tempPath) { |
| 726 | if (form.value.legalIdcPhoto1) { | 803 | if (tempPath) { |
| 727 | uni.uploadFile({ | 804 | uni.uploadFile({ |
| 728 | url: config.baseUrl_api + '/person/info/getPersonInfoFromCert/0', | 805 | url: config.baseUrl_api + '/person/info/getPersonInfoFromCert/0', |
| 729 | filePath: form.value.legalIdcPhoto2, | 806 | filePath: tempPath, |
| 730 | name: 'pic', | 807 | name: 'pic', |
| 731 | header: { | 808 | header: { |
| 732 | 'Authorization': uni.getStorageSync('token') | 809 | 'Authorization': uni.getStorageSync('token') |
| ... | @@ -750,7 +827,19 @@ | ... | @@ -750,7 +827,19 @@ |
| 750 | sourceType: ['album', 'camera'], | 827 | sourceType: ['album', 'camera'], |
| 751 | success: (res) => { | 828 | success: (res) => { |
| 752 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { | 829 | if (res.tempFilePaths && res.tempFilePaths.length > 0) { |
| 753 | form.value.pictures = res.tempFilePaths.join(',') | 830 | uni.showLoading({ title: '上传中...' }) |
| 831 | // 循环上传多张图片 | ||
| 832 | const promises = res.tempFilePaths.map(path => { | ||
| 833 | return api.uploadImg({ tempFilePaths: [path] }) | ||
| 834 | }) | ||
| 835 | Promise.all(promises).then(results => { | ||
| 836 | uni.hideLoading() | ||
| 837 | const urls = results.filter(r => r.code === 200).map(r => r.msg) | ||
| 838 | form.value.pictures = urls.join(',') | ||
| 839 | }).catch(() => { | ||
| 840 | uni.hideLoading() | ||
| 841 | uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 842 | }) | ||
| 754 | } | 843 | } |
| 755 | } | 844 | } |
| 756 | }) | 845 | }) |
| ... | @@ -951,6 +1040,7 @@ | ... | @@ -951,6 +1040,7 @@ |
| 951 | font-size: 28rpx; | 1040 | font-size: 28rpx; |
| 952 | color: #333; | 1041 | color: #333; |
| 953 | margin-right: 10rpx; | 1042 | margin-right: 10rpx; |
| 1043 | width: 100px; | ||
| 954 | } | 1044 | } |
| 955 | 1045 | ||
| 956 | .btn-row { | 1046 | .btn-row { |
| ... | @@ -1154,6 +1244,34 @@ | ... | @@ -1154,6 +1244,34 @@ |
| 1154 | } | 1244 | } |
| 1155 | } | 1245 | } |
| 1156 | 1246 | ||
| 1247 | /* picker 样式 */ | ||
| 1248 | .picker-view { | ||
| 1249 | height: 70rpx; | ||
| 1250 | line-height: 70rpx; | ||
| 1251 | display: flex; | ||
| 1252 | align-items: center; | ||
| 1253 | justify-content: space-between; | ||
| 1254 | padding: 0 20rpx; | ||
| 1255 | box-sizing: border-box; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | .picker-text { | ||
| 1259 | flex: 1; | ||
| 1260 | overflow: hidden; | ||
| 1261 | text-overflow: ellipsis; | ||
| 1262 | white-space: nowrap; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | .arrow-icon { | ||
| 1266 | font-size: 20rpx; | ||
| 1267 | color: #999; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | .placeholder { | ||
| 1271 | color: #999; | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | |||
| 1157 | /* 级联选择器容器 - 修复边框和宽度问题(删除重复定义) */ | 1275 | /* 级联选择器容器 - 修复边框和宽度问题(删除重复定义) */ |
| 1158 | .picker-wrapper { | 1276 | .picker-wrapper { |
| 1159 | border: 1rpx solid #e0e0e0; | 1277 | border: 1rpx solid #e0e0e0; |
| ... | @@ -1200,17 +1318,34 @@ | ... | @@ -1200,17 +1318,34 @@ |
| 1200 | min-height: 70rpx; | 1318 | min-height: 70rpx; |
| 1201 | } | 1319 | } |
| 1202 | 1320 | ||
| 1321 | /* uni-data-picker 弹窗样式 - 列表文字大小 */ | ||
| 1322 | :deep(.item) { | ||
| 1323 | font-size: 32rpx !important; | ||
| 1324 | padding: 24rpx 30rpx !important; | ||
| 1325 | } | ||
| 1326 | :deep(.item-text) { | ||
| 1327 | font-size: 32rpx !important; | ||
| 1328 | } | ||
| 1329 | :deep(.selected-item-text) { | ||
| 1330 | font-size: 32rpx !important; | ||
| 1331 | } | ||
| 1332 | |||
| 1203 | /* 修复uni-forms-item中内容超出问题 */ | 1333 | /* 修复uni-forms-item中内容超出问题 */ |
| 1334 | /* 暂时移除 overflow: hidden 以避免影响下拉组件 */ | ||
| 1335 | /* | ||
| 1204 | :deep(.uni-forms-item__content) { | 1336 | :deep(.uni-forms-item__content) { |
| 1205 | overflow: hidden; | 1337 | overflow: hidden; |
| 1206 | width: 100%; | 1338 | width: 100%; |
| 1207 | } | 1339 | } |
| 1340 | */ | ||
| 1208 | 1341 | ||
| 1209 | /* 确保所有表单元素不超出父容器 */ | 1342 | /* 确保所有表单元素不超出父容器 */ |
| 1343 | /* | ||
| 1210 | :deep(uni-forms-item) { | 1344 | :deep(uni-forms-item) { |
| 1211 | width: 100%; | 1345 | width: 100%; |
| 1212 | overflow: hidden; | 1346 | overflow: hidden; |
| 1213 | } | 1347 | } |
| 1348 | */ | ||
| 1214 | 1349 | ||
| 1215 | /* 修复选择器容器宽度问题 */ | 1350 | /* 修复选择器容器宽度问题 */ |
| 1216 | .picker-wrapper { | 1351 | .picker-wrapper { | ... | ... |
| ... | @@ -219,7 +219,7 @@ | ... | @@ -219,7 +219,7 @@ |
| 219 | display: flex; | 219 | display: flex; |
| 220 | /* #endif */ | 220 | /* #endif */ |
| 221 | align-items: center; | 221 | align-items: center; |
| 222 | padding: 8px 10px; | 222 | padding: 18px 10px; |
| 223 | padding-right: 5px; | 223 | padding-right: 5px; |
| 224 | padding-left: 10px; | 224 | padding-left: 10px; |
| 225 | } | 225 | } | ... | ... |
-
Please register or sign in to post a comment