企业信息补全页面开发
This commit is contained in:
250
components/area-cascade-picker/README.md
Normal file
250
components/area-cascade-picker/README.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# 五级联动地址选择器组件
|
||||
|
||||
## 组件简介
|
||||
|
||||
`area-cascade-picker` 是一个支持省市区县街道社区的五级联动地址选择组件,适用于需要选择详细地址的场景。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- ✅ 五级联动选择(省/市/区/街道/社区)
|
||||
- ✅ 自动级联更新
|
||||
- ✅ 支持取消和确认操作
|
||||
- ✅ 底部弹出式交互
|
||||
- ✅ 支持自定义标题
|
||||
- ✅ 返回完整的地址信息和各级代码
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 引入组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<button @click="openPicker">选择地址</button>
|
||||
<area-cascade-picker ref="areaPicker"></area-cascade-picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import AreaCascadePicker from '@/components/area-cascade-picker/area-cascade-picker.vue'
|
||||
|
||||
const areaPicker = ref(null)
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 打开选择器
|
||||
|
||||
```javascript
|
||||
const openPicker = () => {
|
||||
areaPicker.value?.open({
|
||||
title: '选择地址',
|
||||
maskClick: true,
|
||||
success: (addressData) => {
|
||||
console.log('选择的地址:', addressData)
|
||||
// 处理选择结果
|
||||
},
|
||||
cancel: () => {
|
||||
console.log('取消选择')
|
||||
},
|
||||
change: (addressData) => {
|
||||
console.log('地址变化:', addressData)
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## API 说明
|
||||
|
||||
### open(config)
|
||||
|
||||
打开地址选择器
|
||||
|
||||
#### 参数 config
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| title | String | 否 | '选择地址' | 选择器标题 |
|
||||
| maskClick | Boolean | 否 | false | 是否允许点击遮罩关闭 |
|
||||
| success | Function | 否 | - | 确认选择的回调函数 |
|
||||
| cancel | Function | 否 | - | 取消选择的回调函数 |
|
||||
| change | Function | 否 | - | 选择变化的回调函数 |
|
||||
| defaultValue | Object | 否 | null | 默认选中的地址(暂未实现) |
|
||||
|
||||
#### success 回调参数
|
||||
|
||||
```javascript
|
||||
{
|
||||
address: "新疆维吾尔自治区/喀什地区/喀什市/学府街道/学府社区居委会",
|
||||
province: {
|
||||
code: "650000",
|
||||
name: "新疆维吾尔自治区"
|
||||
},
|
||||
city: {
|
||||
code: "653100",
|
||||
name: "喀什地区"
|
||||
},
|
||||
district: {
|
||||
code: "653101",
|
||||
name: "喀什市"
|
||||
},
|
||||
street: {
|
||||
code: "65310101",
|
||||
name: "学府街道"
|
||||
},
|
||||
community: {
|
||||
code: "6531010101",
|
||||
name: "学府社区居委会"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### close()
|
||||
|
||||
关闭地址选择器
|
||||
|
||||
```javascript
|
||||
areaPicker.value?.close()
|
||||
```
|
||||
|
||||
## 数据格式
|
||||
|
||||
组件使用树形结构的地址数据,格式如下:
|
||||
|
||||
```javascript
|
||||
[
|
||||
{
|
||||
code: '650000', // 行政区划代码
|
||||
name: '新疆维吾尔自治区', // 名称
|
||||
children: [ // 下级行政区
|
||||
{
|
||||
code: '653100',
|
||||
name: '喀什地区',
|
||||
children: [
|
||||
{
|
||||
code: '653101',
|
||||
name: '喀什市',
|
||||
children: [
|
||||
{
|
||||
code: '65310101',
|
||||
name: '学府街道',
|
||||
children: [
|
||||
{
|
||||
code: '6531010101',
|
||||
name: '学府社区居委会'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 企业注册地址选择
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="form-item" @click="selectLocation">
|
||||
<text class="label">企业注册地点</text>
|
||||
<view class="input-content">
|
||||
<text :class="{ placeholder: !formData.address }">
|
||||
{{ formData.address || '请选择注册地点' }}
|
||||
</text>
|
||||
<uni-icons type="arrowright" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<area-cascade-picker ref="areaPicker"></area-cascade-picker>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import AreaCascadePicker from '@/components/area-cascade-picker/area-cascade-picker.vue'
|
||||
|
||||
const areaPicker = ref(null)
|
||||
const formData = reactive({
|
||||
address: '',
|
||||
provinceCode: '',
|
||||
provinceName: '',
|
||||
cityCode: '',
|
||||
cityName: '',
|
||||
districtCode: '',
|
||||
districtName: '',
|
||||
streetCode: '',
|
||||
streetName: '',
|
||||
communityCode: '',
|
||||
communityName: ''
|
||||
})
|
||||
|
||||
const selectLocation = () => {
|
||||
areaPicker.value?.open({
|
||||
title: '选择企业注册地点',
|
||||
maskClick: true,
|
||||
success: (addressData) => {
|
||||
// 保存完整地址
|
||||
formData.address = addressData.address
|
||||
|
||||
// 保存各级信息
|
||||
formData.provinceCode = addressData.province?.code
|
||||
formData.provinceName = addressData.province?.name
|
||||
formData.cityCode = addressData.city?.code
|
||||
formData.cityName = addressData.city?.name
|
||||
formData.districtCode = addressData.district?.code
|
||||
formData.districtName = addressData.district?.name
|
||||
formData.streetCode = addressData.street?.code
|
||||
formData.streetName = addressData.street?.name
|
||||
formData.communityCode = addressData.community?.code
|
||||
formData.communityName = addressData.community?.name
|
||||
|
||||
console.log('已选择地址:', formData)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据来源**:当前使用本地模拟数据,生产环境建议接入后端API
|
||||
2. **数据更新**:如需接入后端API,修改 `loadAreaData` 方法即可
|
||||
3. **性能优化**:地址数据量大时,建议使用懒加载
|
||||
4. **兼容性**:支持 H5、微信小程序等多端
|
||||
|
||||
## 接入后端API
|
||||
|
||||
在组件的 `loadAreaData` 方法中取消注释并配置API:
|
||||
|
||||
```javascript
|
||||
async loadAreaData() {
|
||||
try {
|
||||
const resp = await uni.request({
|
||||
url: '/app/common/area/cascade',
|
||||
method: 'GET'
|
||||
});
|
||||
if (resp.statusCode === 200 && resp.data && resp.data.data) {
|
||||
this.areaData = resp.data.data;
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载地区数据失败:', error);
|
||||
}
|
||||
|
||||
// 失败时使用模拟数据
|
||||
this.areaData = this.getMockData();
|
||||
}
|
||||
```
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2025-10-21)
|
||||
- ✨ 初始版本
|
||||
- ✅ 实现五级联动选择功能
|
||||
- ✅ 支持省市区县街道社区选择
|
||||
- ✅ 提供完整的地址信息返回
|
||||
|
426
components/area-cascade-picker/area-cascade-picker.vue
Normal file
426
components/area-cascade-picker/area-cascade-picker.vue
Normal file
@@ -0,0 +1,426 @@
|
||||
<template>
|
||||
<uni-popup
|
||||
ref="popup"
|
||||
type="bottom"
|
||||
borderRadius="10px 10px 0 0"
|
||||
background-color="#FFFFFF"
|
||||
:mask-click="maskClick"
|
||||
>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<view class="btn-cancel" @click="cancel">取消</view>
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="btn-confirm" @click="confirm">确认</view>
|
||||
</view>
|
||||
<view class="popup-list">
|
||||
<picker-view
|
||||
indicator-style="height: 84rpx;"
|
||||
:value="selectedIndex"
|
||||
@change="bindChange"
|
||||
class="picker-view"
|
||||
>
|
||||
<!-- 省 -->
|
||||
<picker-view-column>
|
||||
<view
|
||||
v-for="(item, index) in provinceList"
|
||||
:key="item.code"
|
||||
class="item"
|
||||
:class="{ 'item-active': selectedIndex[0] === index }"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
|
||||
<!-- 市 -->
|
||||
<picker-view-column>
|
||||
<view
|
||||
v-for="(item, index) in cityList"
|
||||
:key="item.code"
|
||||
class="item"
|
||||
:class="{ 'item-active': selectedIndex[1] === index }"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
|
||||
<!-- 区县 -->
|
||||
<picker-view-column>
|
||||
<view
|
||||
v-for="(item, index) in districtList"
|
||||
:key="item.code"
|
||||
class="item"
|
||||
:class="{ 'item-active': selectedIndex[2] === index }"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
|
||||
<!-- 街道 -->
|
||||
<picker-view-column>
|
||||
<view
|
||||
v-for="(item, index) in streetList"
|
||||
:key="item.code"
|
||||
class="item"
|
||||
:class="{ 'item-active': selectedIndex[3] === index }"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
|
||||
<!-- 社区/居委会 -->
|
||||
<picker-view-column>
|
||||
<view
|
||||
v-for="(item, index) in communityList"
|
||||
:key="item.code"
|
||||
class="item"
|
||||
:class="{ 'item-active': selectedIndex[4] === index }"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addressJson from '@/static/json/xinjiang.json';
|
||||
export default {
|
||||
name: 'AreaCascadePicker',
|
||||
data() {
|
||||
return {
|
||||
maskClick: false,
|
||||
title: '选择地址',
|
||||
confirmCallback: null,
|
||||
cancelCallback: null,
|
||||
changeCallback: null,
|
||||
selectedIndex: [0, 0, 0, 0, 0],
|
||||
// 原始数据
|
||||
areaData: [],
|
||||
// 各级列表
|
||||
provinceList: [],
|
||||
cityList: [],
|
||||
districtList: [],
|
||||
streetList: [],
|
||||
communityList: [],
|
||||
// 当前选中的项
|
||||
selectedProvince: null,
|
||||
selectedCity: null,
|
||||
selectedDistrict: null,
|
||||
selectedStreet: null,
|
||||
selectedCommunity: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async open(newConfig = {}) {
|
||||
const {
|
||||
title,
|
||||
success,
|
||||
cancel,
|
||||
change,
|
||||
maskClick = false,
|
||||
defaultValue = null,
|
||||
} = newConfig;
|
||||
|
||||
this.reset();
|
||||
if (title) this.title = title;
|
||||
if (typeof success === 'function') this.confirmCallback = success;
|
||||
if (typeof cancel === 'function') this.cancelCallback = cancel;
|
||||
if (typeof change === 'function') this.changeCallback = change;
|
||||
this.maskClick = maskClick;
|
||||
|
||||
// 加载地区数据
|
||||
await this.loadAreaData();
|
||||
|
||||
// 初始化列表
|
||||
this.initLists();
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.popup.open();
|
||||
});
|
||||
},
|
||||
|
||||
async loadAreaData() {
|
||||
try {
|
||||
// 尝试调用后端API获取地区数据
|
||||
// 如果后端API不存在,将使用模拟数据
|
||||
console.log('正在加载地区数据...');
|
||||
// const resp = await uni.request({
|
||||
// url: '/app/common/area/cascade',
|
||||
// method: 'GET'
|
||||
// });
|
||||
// if (resp.statusCode === 200 && resp.data && resp.data.data) {
|
||||
// this.areaData = resp.data.data;
|
||||
// }
|
||||
|
||||
// 暂时使用模拟数据
|
||||
this.areaData = this.getMockData();
|
||||
} catch (error) {
|
||||
console.error('加载地区数据失败:', error);
|
||||
// 如果后端API不存在,使用模拟数据
|
||||
this.areaData = this.getMockData();
|
||||
}
|
||||
},
|
||||
|
||||
initLists() {
|
||||
// 初始化省列表
|
||||
this.provinceList = this.areaData;
|
||||
|
||||
if (this.provinceList.length > 0) {
|
||||
this.selectedProvince = this.provinceList[0];
|
||||
this.updateCityList();
|
||||
}
|
||||
},
|
||||
|
||||
updateCityList() {
|
||||
if (!this.selectedProvince || !this.selectedProvince.children) {
|
||||
this.cityList = [];
|
||||
this.districtList = [];
|
||||
this.streetList = [];
|
||||
this.communityList = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.cityList = this.selectedProvince.children;
|
||||
this.selectedIndex[1] = 0;
|
||||
|
||||
if (this.cityList.length > 0) {
|
||||
this.selectedCity = this.cityList[0];
|
||||
this.updateDistrictList();
|
||||
}
|
||||
},
|
||||
|
||||
updateDistrictList() {
|
||||
if (!this.selectedCity || !this.selectedCity.children) {
|
||||
this.districtList = [];
|
||||
this.streetList = [];
|
||||
this.communityList = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.districtList = this.selectedCity.children;
|
||||
this.selectedIndex[2] = 0;
|
||||
|
||||
if (this.districtList.length > 0) {
|
||||
this.selectedDistrict = this.districtList[0];
|
||||
this.updateStreetList();
|
||||
}
|
||||
},
|
||||
|
||||
updateStreetList() {
|
||||
if (!this.selectedDistrict || !this.selectedDistrict.children) {
|
||||
this.streetList = [];
|
||||
this.communityList = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.streetList = this.selectedDistrict.children;
|
||||
this.selectedIndex[3] = 0;
|
||||
|
||||
if (this.streetList.length > 0) {
|
||||
this.selectedStreet = this.streetList[0];
|
||||
this.updateCommunityList();
|
||||
}
|
||||
},
|
||||
|
||||
updateCommunityList() {
|
||||
if (!this.selectedStreet || !this.selectedStreet.children) {
|
||||
this.communityList = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.communityList = this.selectedStreet.children;
|
||||
this.selectedIndex[4] = 0;
|
||||
|
||||
if (this.communityList.length > 0) {
|
||||
this.selectedCommunity = this.communityList[0];
|
||||
}
|
||||
},
|
||||
|
||||
bindChange(e) {
|
||||
const newIndex = e.detail.value;
|
||||
|
||||
// 检查哪一列发生了变化
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (newIndex[i] !== this.selectedIndex[i]) {
|
||||
this.selectedIndex[i] = newIndex[i];
|
||||
|
||||
// 根据变化的列更新后续列
|
||||
if (i === 0) {
|
||||
// 省变化
|
||||
this.selectedProvince = this.provinceList[newIndex[0]];
|
||||
this.updateCityList();
|
||||
} else if (i === 1) {
|
||||
// 市变化
|
||||
this.selectedCity = this.cityList[newIndex[1]];
|
||||
this.updateDistrictList();
|
||||
} else if (i === 2) {
|
||||
// 区县变化
|
||||
this.selectedDistrict = this.districtList[newIndex[2]];
|
||||
this.updateStreetList();
|
||||
} else if (i === 3) {
|
||||
// 街道变化
|
||||
this.selectedStreet = this.streetList[newIndex[3]];
|
||||
this.updateCommunityList();
|
||||
} else if (i === 4) {
|
||||
// 社区变化
|
||||
this.selectedCommunity = this.communityList[newIndex[4]];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.changeCallback) {
|
||||
this.changeCallback(this.getSelectedAddress());
|
||||
}
|
||||
},
|
||||
|
||||
getSelectedAddress() {
|
||||
const parts = [];
|
||||
if (this.selectedProvince) parts.push(this.selectedProvince.name);
|
||||
if (this.selectedCity) parts.push(this.selectedCity.name);
|
||||
if (this.selectedDistrict) parts.push(this.selectedDistrict.name);
|
||||
if (this.selectedStreet) parts.push(this.selectedStreet.name);
|
||||
if (this.selectedCommunity) parts.push(this.selectedCommunity.name);
|
||||
|
||||
return {
|
||||
address: parts.join('/'),
|
||||
province: this.selectedProvince,
|
||||
city: this.selectedCity,
|
||||
district: this.selectedDistrict,
|
||||
street: this.selectedStreet,
|
||||
community: this.selectedCommunity,
|
||||
};
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$refs.popup.close();
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.clickCallback(this.cancelCallback);
|
||||
},
|
||||
|
||||
confirm() {
|
||||
this.clickCallback(this.confirmCallback);
|
||||
},
|
||||
|
||||
async clickCallback(callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
this.$refs.popup.close();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await callback(this.getSelectedAddress());
|
||||
if (result !== false) {
|
||||
this.$refs.popup.close();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('callback 执行出错:', error);
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.maskClick = false;
|
||||
this.confirmCallback = null;
|
||||
this.cancelCallback = null;
|
||||
this.changeCallback = null;
|
||||
this.selectedIndex = [0, 0, 0, 0, 0];
|
||||
this.provinceList = [];
|
||||
this.cityList = [];
|
||||
this.districtList = [];
|
||||
this.streetList = [];
|
||||
this.communityList = [];
|
||||
},
|
||||
|
||||
// 模拟数据(用于演示)
|
||||
getMockData() {
|
||||
return addressJson
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-content {
|
||||
color: #000000;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.popup-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
height: calc(60vh - 100rpx);
|
||||
margin-top: 20rpx;
|
||||
|
||||
.uni-picker-view-mask {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.item {
|
||||
line-height: 84rpx;
|
||||
height: 84rpx;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #cccccc;
|
||||
padding: 0 4rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-active {
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.uni-picker-view-indicator:after {
|
||||
border-color: #e3e3e3;
|
||||
}
|
||||
|
||||
.uni-picker-view-indicator:before {
|
||||
border-color: #e3e3e3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 40rpx 40rpx 10rpx 40rpx;
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #666d7f;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #256bfa;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -116,6 +116,7 @@ const handleItemClick = (e) => {
|
||||
}
|
||||
|
||||
/* 表格 */
|
||||
/* #ifndef MP-WEIXIN */
|
||||
table {
|
||||
// display: block; /* 让表格可滚动 */
|
||||
// width: 100%;
|
||||
@@ -147,6 +148,7 @@ tr:hover {
|
||||
background-color: #f1f1f1;
|
||||
transition: 0.3s;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/* 代码块 */
|
||||
pre,
|
||||
@@ -207,11 +209,13 @@ pre code:empty {
|
||||
cursor: pointer;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
/* #ifndef MP-WEIXIN */
|
||||
.copy-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: #259939;
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
pre.hljs {
|
||||
padding: 0 24rpx;
|
||||
@@ -246,6 +250,7 @@ ol {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* #ifndef MP-WEIXIN */
|
||||
#markdown-content ::v-deep div > pre:first-of-type {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
@@ -254,6 +259,7 @@ ol {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
/* #endif */
|
||||
.markdownRich > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@@ -14,6 +14,33 @@
|
||||
<view class="auth-subtitle">需要您授权手机号登录</view>
|
||||
</view>
|
||||
|
||||
<!-- 角色选择 -->
|
||||
<view class="role-select">
|
||||
<view class="role-title">请选择您的角色</view>
|
||||
<view class="role-options">
|
||||
<view
|
||||
class="role-item"
|
||||
:class="{ active: userType === 1 }"
|
||||
@click="selectRole(1)"
|
||||
>
|
||||
<view class="role-icon">
|
||||
<uni-icons type="person" size="32" :color="userType === 1 ? '#256BFA' : '#999'"></uni-icons>
|
||||
</view>
|
||||
<view class="role-text">我是求职者</view>
|
||||
</view>
|
||||
<view
|
||||
class="role-item"
|
||||
:class="{ active: userType === 0 }"
|
||||
@click="selectRole(0)"
|
||||
>
|
||||
<view class="role-icon">
|
||||
<uni-icons type="shop" size="32" :color="userType === 0 ? '#256BFA' : '#999'"></uni-icons>
|
||||
</view>
|
||||
<view class="role-text">我是招聘者</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 授权说明 -->
|
||||
<view class="auth-tips">
|
||||
<view class="tip-item">
|
||||
@@ -80,11 +107,13 @@ const { $api } = inject('globalFunction');
|
||||
const { loginSetToken } = useUserStore();
|
||||
|
||||
const popup = ref(null);
|
||||
const userType = ref(null); // 用户角色:1-求职者,0-企业
|
||||
const emit = defineEmits(['success', 'cancel']);
|
||||
|
||||
// 打开弹窗
|
||||
const open = () => {
|
||||
popup.value?.open();
|
||||
userType.value = null; // 重置角色选择
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
@@ -93,46 +122,84 @@ const close = () => {
|
||||
emit('cancel');
|
||||
};
|
||||
|
||||
// 微信小程序获取手机号
|
||||
// 选择角色
|
||||
const selectRole = (type) => {
|
||||
userType.value = type;
|
||||
};
|
||||
|
||||
// 验证角色是否已选择
|
||||
const validateRole = () => {
|
||||
if (userType.value === null) {
|
||||
$api.msg('请先选择您的角色');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const getPhoneNumber = (e) => {
|
||||
console.log('获取手机号:', e);
|
||||
|
||||
// 验证角色是否已选择
|
||||
if (!validateRole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||
const { code, encryptedData, iv } = e.detail;
|
||||
|
||||
// 调用后端接口进行登录
|
||||
uni.showLoading({ title: '登录中...' });
|
||||
|
||||
$api.createRequest('/app/appLogin', {
|
||||
code,
|
||||
encryptedData,
|
||||
iv
|
||||
}, 'post').then((resData) => {
|
||||
uni.hideLoading();
|
||||
|
||||
if (resData.token) {
|
||||
// 登录成功,存储token
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
$api.msg('登录成功');
|
||||
close();
|
||||
emit('success');
|
||||
|
||||
// 如果用户信息不完整,跳转到完善信息页面
|
||||
if (!resume.data.jobTitleId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login?step=1'
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
$api.msg('获取用户信息失败');
|
||||
});
|
||||
} else {
|
||||
$api.msg('登录失败,请重试');
|
||||
}
|
||||
}).catch((err) => {
|
||||
uni.hideLoading();
|
||||
$api.msg(err.msg || '登录失败,请重试');
|
||||
});
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
console.log('微信登录code获取成功:', loginRes.code);
|
||||
const { encryptedData, iv } = e.detail;
|
||||
const code = loginRes.code; // 使用wx.login返回的code
|
||||
|
||||
// 调用后端接口进行登录
|
||||
uni.showLoading({ title: '登录中...' });
|
||||
|
||||
$api.createRequest('/app/appLogin', {
|
||||
code,
|
||||
encryptedData,
|
||||
iv,
|
||||
userType: userType.value
|
||||
}, 'post').then((resData) => {
|
||||
uni.hideLoading();
|
||||
|
||||
if (resData.token) {
|
||||
// 登录成功,存储token
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
$api.msg('登录成功');
|
||||
close();
|
||||
emit('success');
|
||||
|
||||
// 根据用户类型跳转到不同的信息补全页面
|
||||
if (!resume.data.jobTitleId) {
|
||||
if (userType.value === 1) {
|
||||
// 求职者跳转到个人信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/complete-info?step=1'
|
||||
});
|
||||
} else if (userType.value === 0) {
|
||||
// 招聘者跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info'
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(() => {
|
||||
$api.msg('获取用户信息失败');
|
||||
});
|
||||
} else {
|
||||
$api.msg('登录失败,请重试');
|
||||
}
|
||||
}).catch((err) => {
|
||||
uni.hideLoading();
|
||||
$api.msg(err.msg || '登录失败,请重试');
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取微信登录code失败:', err);
|
||||
$api.msg('获取登录信息失败,请重试');
|
||||
}
|
||||
});
|
||||
} else if (e.detail.errMsg === 'getPhoneNumber:fail user deny') {
|
||||
$api.msg('您取消了授权');
|
||||
} else {
|
||||
@@ -142,6 +209,11 @@ const getPhoneNumber = (e) => {
|
||||
|
||||
// H5/App 微信登录
|
||||
const wxLogin = () => {
|
||||
// 验证角色是否已选择
|
||||
if (!validateRole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
// H5网页微信登录逻辑
|
||||
uni.showLoading({ title: '登录中...' });
|
||||
@@ -154,7 +226,8 @@ const wxLogin = () => {
|
||||
|
||||
// 调用后端接口进行登录
|
||||
$api.createRequest('/app/appLogin', {
|
||||
code: loginRes.code
|
||||
code: loginRes.code,
|
||||
userType: userType.value
|
||||
}, 'post').then((resData) => {
|
||||
uni.hideLoading();
|
||||
|
||||
@@ -165,9 +238,17 @@ const wxLogin = () => {
|
||||
emit('success');
|
||||
|
||||
if (!resume.data.jobTitleId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login?step=1'
|
||||
});
|
||||
if (userType.value === 1) {
|
||||
// 求职者跳转到个人信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/complete-info?step=1'
|
||||
});
|
||||
} else if (userType.value === 0) {
|
||||
// 招聘者跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -199,7 +280,8 @@ const wxLogin = () => {
|
||||
|
||||
// 调用后端接口进行登录
|
||||
$api.createRequest('/app/appLogin', {
|
||||
code: loginRes.code
|
||||
code: loginRes.code,
|
||||
userType: userType.value
|
||||
}, 'post').then((resData) => {
|
||||
if (resData.token) {
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
@@ -208,9 +290,17 @@ const wxLogin = () => {
|
||||
emit('success');
|
||||
|
||||
if (!resume.data.jobTitleId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login?step=1'
|
||||
});
|
||||
if (userType.value === 1) {
|
||||
// 求职者跳转到个人信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/complete-info?step=1'
|
||||
});
|
||||
} else if (userType.value === 0) {
|
||||
// 招聘者跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -245,9 +335,17 @@ const testLogin = () => {
|
||||
emit('success');
|
||||
|
||||
if (!resume.data.jobTitleId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login?step=1'
|
||||
});
|
||||
if (userType.value === 1) {
|
||||
// 求职者跳转到个人信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/complete-info?step=1'
|
||||
});
|
||||
} else if (userType.value === 0) {
|
||||
// 招聘者跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info'
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(() => {
|
||||
$api.msg('获取用户信息失败');
|
||||
@@ -320,6 +418,47 @@ defineExpose({
|
||||
font-size: 28rpx
|
||||
color: #666666
|
||||
|
||||
.role-select
|
||||
margin-bottom: 32rpx
|
||||
|
||||
.role-title
|
||||
font-size: 28rpx
|
||||
font-weight: 500
|
||||
color: #333333
|
||||
margin-bottom: 20rpx
|
||||
text-align: center
|
||||
|
||||
.role-options
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
gap: 20rpx
|
||||
|
||||
.role-item
|
||||
flex: 1
|
||||
background: #F7F8FA
|
||||
border: 2rpx solid #E5E5E5
|
||||
border-radius: 16rpx
|
||||
padding: 32rpx 20rpx
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
position: relative
|
||||
transition: all 0.3s ease
|
||||
cursor: pointer
|
||||
|
||||
&.active
|
||||
background: #F0F5FF
|
||||
border-color: #256BFA
|
||||
box-shadow: 0 4rpx 12rpx rgba(37, 107, 250, 0.15)
|
||||
|
||||
.role-icon
|
||||
margin-bottom: 16rpx
|
||||
|
||||
.role-text
|
||||
font-size: 28rpx
|
||||
color: #333333
|
||||
font-weight: 500
|
||||
|
||||
.auth-tips
|
||||
background: #F7F8FA
|
||||
border-radius: 16rpx
|
||||
|
Reference in New Issue
Block a user