|
|
@@ -52,7 +52,7 @@
|
|
|
<view class="list-item no-border">
|
|
|
<text class="item-title">所属站点</text>
|
|
|
<view class="item-right">
|
|
|
- <text class="item-value">深圳市龙华区民治街道第一站</text>
|
|
|
+ <text class="item-value">{{ userInfo.stationName || '未分配站点' }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -67,7 +67,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 城市选择弹窗 (模拟) -->
|
|
|
+ <!-- 城市选择弹窗 (级联版,与我要加入页面一致) -->
|
|
|
<view class="popup-mask" v-if="isCityPickerShow" @click="closeCityPicker">
|
|
|
<view class="popup-content" @click.stop>
|
|
|
<view class="popup-header-row">
|
|
|
@@ -75,38 +75,41 @@
|
|
|
<text class="popup-title-text">请选择工作城市</text>
|
|
|
<text class="popup-btn-confirm" @click="confirmCity">确定</text>
|
|
|
</view>
|
|
|
- <view class="city-tabs">
|
|
|
- <view
|
|
|
- class="city-tab-item"
|
|
|
- :class="{ 'active': cityStep > 0, 'active-red': cityStep === 0 }"
|
|
|
- @click="changeCityStep(0)">
|
|
|
- {{ selectedProvince || '请选择' }}
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="city-tab-item"
|
|
|
- :class="{ 'active': cityStep > 1, 'active-red': cityStep === 1 }"
|
|
|
- v-if="selectedProvince"
|
|
|
- @click="changeCityStep(1)">
|
|
|
- {{ selectedCity || '请选择' }}
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="city-tab-item"
|
|
|
- :class="{ 'active-red': cityStep === 2 }"
|
|
|
- v-if="selectedCity"
|
|
|
- @click="changeCityStep(2)">
|
|
|
- {{ selectedDistrict || '请选择' }}
|
|
|
+ <view class="picker-body">
|
|
|
+ <!-- 左侧:垂直路径 -->
|
|
|
+ <view class="timeline-area">
|
|
|
+ <view
|
|
|
+ class="timeline-item"
|
|
|
+ v-for="(item, index) in selectedPathway"
|
|
|
+ :key="index"
|
|
|
+ @click="jumpToStep(index)"
|
|
|
+ >
|
|
|
+ <view class="timeline-dot"></view>
|
|
|
+ <text>{{ item.name }}</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="timeline-item active"
|
|
|
+ v-if="selectStep === selectedPathway.length"
|
|
|
+ >
|
|
|
+ <view class="timeline-dot"></view>
|
|
|
+ <text>请选择</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
+ <!-- 右侧:待选项列表 -->
|
|
|
+ <scroll-view scroll-y class="list-area">
|
|
|
+ <view
|
|
|
+ class="list-item"
|
|
|
+ v-for="item in currentCityList"
|
|
|
+ :key="item.id"
|
|
|
+ @click="selectCityItem(item)"
|
|
|
+ >
|
|
|
+ {{ item.name }}
|
|
|
+ </view>
|
|
|
+ <view v-if="currentCityList.length === 0" style="padding:20rpx;color:#999">
|
|
|
+ 无数据
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
</view>
|
|
|
- <scroll-view scroll-y class="city-list">
|
|
|
- <view
|
|
|
- class="city-item"
|
|
|
- v-for="(item, index) in currentList"
|
|
|
- :key="index"
|
|
|
- @click="selectItem(item)">
|
|
|
- {{ item }}
|
|
|
- <text v-if="isSelected(item)" style="float: right; color: #FF5722;">✓</text>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
@@ -114,55 +117,32 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+// 引入 API @author steelwei
|
|
|
+import { getMyProfile, updateAvatar, updateName, updateStatus, updateCity, uploadFile, getAreaChildren } from '@/api/fulfiller'
|
|
|
+
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
userInfo: {
|
|
|
- name: '张*哥',
|
|
|
- workType: '全职',
|
|
|
- workStatus: '接单中',
|
|
|
- city: '广东省 深圳市 龙华区',
|
|
|
- avatar: '/static/touxiang.png'
|
|
|
+ name: '',
|
|
|
+ workType: '',
|
|
|
+ workStatus: '',
|
|
|
+ city: '',
|
|
|
+ avatar: '/static/touxiang.png',
|
|
|
+ stationName: ''
|
|
|
},
|
|
|
isStatusPickerShow: false,
|
|
|
isCityPickerShow: false,
|
|
|
|
|
|
- // 城市选择相关
|
|
|
- cityStep: 0, // 0: 省, 1: 市, 2: 区
|
|
|
- selectedProvince: '',
|
|
|
- selectedCity: '',
|
|
|
- selectedDistrict: '',
|
|
|
-
|
|
|
- // 模拟数据
|
|
|
- provinces: ['广东省', '湖南省', '江西省'],
|
|
|
- cities: {
|
|
|
- '广东省': ['深圳市', '广州市', '东莞市'],
|
|
|
- '湖南省': ['长沙市', '株洲市'],
|
|
|
- '江西省': ['南昌市', '九江市']
|
|
|
- },
|
|
|
- districts: {
|
|
|
- '深圳市': ['龙华区', '南山区', '福田区', '宝安区'],
|
|
|
- '广州市': ['天河区', '越秀区', '海珠区'],
|
|
|
- '东莞市': ['南城区', '东城区'],
|
|
|
- '长沙市': ['岳麓区', '芙蓉区'],
|
|
|
- '南昌市': ['红谷滩区', '东湖区']
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- computed: {
|
|
|
- currentList() {
|
|
|
- if (this.cityStep === 0) {
|
|
|
- return this.provinces;
|
|
|
- } else if (this.cityStep === 1) {
|
|
|
- return this.cities[this.selectedProvince] || [];
|
|
|
- } else if (this.cityStep === 2) {
|
|
|
- return this.districts[this.selectedCity] || [];
|
|
|
- }
|
|
|
- return [];
|
|
|
+ // 城市级联选择器(与我要加入页面一致)
|
|
|
+ selectStep: 0,
|
|
|
+ selectedPathway: [],
|
|
|
+ currentCityList: [],
|
|
|
+ selectedCityId: null
|
|
|
}
|
|
|
},
|
|
|
onLoad() {
|
|
|
- // 监听姓名修改
|
|
|
+ this.loadUserInfo();
|
|
|
uni.$on('updateName', (newName) => {
|
|
|
this.userInfo.name = newName;
|
|
|
});
|
|
|
@@ -171,87 +151,200 @@ export default {
|
|
|
uni.$off('updateName');
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 加载用户信息 @author steelwei
|
|
|
+ async loadUserInfo() {
|
|
|
+ uni.showLoading({ title: '加载中...' });
|
|
|
+ try {
|
|
|
+ const res = await getMyProfile();
|
|
|
+ if (res.code === 200) {
|
|
|
+ const data = res.data;
|
|
|
+ this.userInfo = {
|
|
|
+ name: data.realName || data.name,
|
|
|
+ workType: data.workType === 'full_time' ? '全职' : '兼职',
|
|
|
+ workStatus: this.formatStatus(data.status),
|
|
|
+ city: data.cityName || '',
|
|
|
+ avatar: data.avatarUrl || '/static/touxiang.png',
|
|
|
+ stationName: data.stationName || '未分配站点'
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.msg || '加载失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载用户信息失败:', error);
|
|
|
+ uni.showToast({ title: '网络错误', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 格式化状态 @author steelwei
|
|
|
+ formatStatus(status) {
|
|
|
+ const statusMap = {
|
|
|
+ 'busy': '接单中',
|
|
|
+ 'resting': '休息中',
|
|
|
+ 'disabled': '已禁用'
|
|
|
+ };
|
|
|
+ return statusMap[status] || status;
|
|
|
+ },
|
|
|
+
|
|
|
navBack() {
|
|
|
- uni.navigateBack({
|
|
|
- delta: 1
|
|
|
- });
|
|
|
+ uni.navigateBack({ delta: 1 });
|
|
|
},
|
|
|
+
|
|
|
+ // 修改头像 @author steelwei
|
|
|
changeAvatar() {
|
|
|
uni.chooseImage({
|
|
|
count: 1,
|
|
|
- success: (res) => {
|
|
|
- console.log(res.tempFilePaths);
|
|
|
- this.userInfo.avatar = res.tempFilePaths[0];
|
|
|
+ success: async (res) => {
|
|
|
+ const tempFilePath = res.tempFilePaths[0];
|
|
|
+
|
|
|
+ // 上传图片到服务器
|
|
|
+ uni.showLoading({ title: '上传中...' });
|
|
|
+ try {
|
|
|
+ const uploadRes = await uploadFile(tempFilePath);
|
|
|
+ if (uploadRes.code === 200) {
|
|
|
+ const avatarUrl = uploadRes.data.url;
|
|
|
+
|
|
|
+ // 调用接口更新头像
|
|
|
+ const result = await updateAvatar(avatarUrl);
|
|
|
+ if (result.code === 200) {
|
|
|
+ this.userInfo.avatar = avatarUrl;
|
|
|
+ uni.showToast({ title: '修改成功', icon: 'success' });
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: result.msg || '修改失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('修改头像失败:', error);
|
|
|
+ uni.showToast({ title: '上传失败', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
+
|
|
|
editName() {
|
|
|
uni.navigateTo({
|
|
|
url: `/pages/mine/settings/profile/edit-name?name=${this.userInfo.name}`
|
|
|
});
|
|
|
},
|
|
|
- toggleWorkType() {
|
|
|
- // 简单模拟切换
|
|
|
- this.userInfo.workType = this.userInfo.workType === '全职' ? '兼职' : '全职';
|
|
|
- },
|
|
|
+
|
|
|
showStatusPicker() {
|
|
|
this.isStatusPickerShow = true;
|
|
|
},
|
|
|
+
|
|
|
closeStatusPicker() {
|
|
|
this.isStatusPickerShow = false;
|
|
|
},
|
|
|
- selectStatus(status) {
|
|
|
- this.userInfo.workStatus = status;
|
|
|
- this.closeStatusPicker();
|
|
|
+
|
|
|
+ // 选择状态 @author steelwei
|
|
|
+ async selectStatus(statusText) {
|
|
|
+ const statusMap = {
|
|
|
+ '接单中': 'busy',
|
|
|
+ '休息中': 'resting'
|
|
|
+ };
|
|
|
+ const status = statusMap[statusText];
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await updateStatus(status);
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.userInfo.workStatus = statusText;
|
|
|
+ uni.showToast({ title: '状态已更新', icon: 'success' });
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.msg || '修改失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('修改状态失败:', error);
|
|
|
+ uni.showToast({ title: '网络错误', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ this.closeStatusPicker();
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
- // 城市选择逻辑
|
|
|
- showCityPicker() {
|
|
|
+ // 城市级联选择器(与我要加入页面一致) @author steelwei
|
|
|
+ async showCityPicker() {
|
|
|
this.isCityPickerShow = true;
|
|
|
- // 初始化/重置
|
|
|
- this.cityStep = 0;
|
|
|
- this.selectedProvince = '';
|
|
|
- this.selectedCity = '';
|
|
|
- this.selectedDistrict = '';
|
|
|
-
|
|
|
- // 如果已有值,尝试回显 (这里简化处理,只重置)
|
|
|
- // 实际开发可解析 this.userInfo.city 进行回显
|
|
|
+ if (this.selectedPathway.length === 0) {
|
|
|
+ await this.resetCityPicker();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async resetCityPicker() {
|
|
|
+ this.selectStep = 0;
|
|
|
+ this.selectedPathway = [];
|
|
|
+ await this.loadAreaChildren(0);
|
|
|
},
|
|
|
closeCityPicker() {
|
|
|
this.isCityPickerShow = false;
|
|
|
},
|
|
|
- changeCityStep(step) {
|
|
|
- this.cityStep = step;
|
|
|
- },
|
|
|
- selectItem(item) {
|
|
|
- if (this.cityStep === 0) {
|
|
|
- this.selectedProvince = item;
|
|
|
- this.cityStep = 1;
|
|
|
- this.selectedCity = ''; // 重置下级
|
|
|
- this.selectedDistrict = '';
|
|
|
- } else if (this.cityStep === 1) {
|
|
|
- this.selectedCity = item;
|
|
|
- this.cityStep = 2;
|
|
|
- this.selectedDistrict = '';
|
|
|
- } else if (this.cityStep === 2) {
|
|
|
- this.selectedDistrict = item;
|
|
|
+ async loadAreaChildren(parentId) {
|
|
|
+ try {
|
|
|
+ const res = await getAreaChildren(parentId);
|
|
|
+ // 城市选择器只显示 城市(0) 和 区域(1),不显示站点(2)
|
|
|
+ this.currentCityList = (res.data || [])
|
|
|
+ .filter(item => item.type !== 2)
|
|
|
+ .map(item => ({
|
|
|
+ id: item.id,
|
|
|
+ name: item.name,
|
|
|
+ type: item.type,
|
|
|
+ parentId: item.parentId
|
|
|
+ }));
|
|
|
+ } catch (err) {
|
|
|
+ console.error('加载区域数据失败:', err);
|
|
|
+ this.currentCityList = [];
|
|
|
}
|
|
|
},
|
|
|
- isSelected(item) {
|
|
|
- if (this.cityStep === 0) return this.selectedProvince === item;
|
|
|
- if (this.cityStep === 1) return this.selectedCity === item;
|
|
|
- if (this.cityStep === 2) return this.selectedDistrict === item;
|
|
|
- return false;
|
|
|
+ async selectCityItem(item) {
|
|
|
+ this.selectedPathway[this.selectStep] = item;
|
|
|
+ // type: 0=城市, 1=区域
|
|
|
+ if (item.type === 0) {
|
|
|
+ this.selectStep++;
|
|
|
+ this.selectedPathway = this.selectedPathway.slice(0, this.selectStep);
|
|
|
+ await this.loadAreaChildren(item.id);
|
|
|
+ if (this.currentCityList.length === 0) {
|
|
|
+ this.selectedCityId = item.id;
|
|
|
+ this.confirmCity();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 区域级(1)选完即确认
|
|
|
+ this.selectedCityId = item.id;
|
|
|
+ this.confirmCity();
|
|
|
+ }
|
|
|
},
|
|
|
- confirmCity() {
|
|
|
- if (this.selectedProvince && this.selectedCity && this.selectedDistrict) {
|
|
|
- this.userInfo.city = `${this.selectedProvince} ${this.selectedCity} ${this.selectedDistrict}`;
|
|
|
- this.closeCityPicker();
|
|
|
+ async jumpToStep(step) {
|
|
|
+ this.selectStep = step;
|
|
|
+ if (step === 0) {
|
|
|
+ await this.loadAreaChildren(0);
|
|
|
} else {
|
|
|
- uni.showToast({
|
|
|
- title: '请选择完整的省市区',
|
|
|
- icon: 'none'
|
|
|
- });
|
|
|
+ const parent = this.selectedPathway[step - 1];
|
|
|
+ if (parent) {
|
|
|
+ await this.loadAreaChildren(parent.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 确认城市选择 @author steelwei
|
|
|
+ async confirmCity() {
|
|
|
+ if (this.selectedPathway.length === 0) {
|
|
|
+ uni.showToast({ title: '请选择城市', icon: 'none' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const cityName = this.selectedPathway.map(i => i.name).join(' ');
|
|
|
+ const cityCode = String(this.selectedCityId);
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await updateCity(cityCode, cityName);
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.userInfo.city = cityName;
|
|
|
+ uni.showToast({ title: '修改成功', icon: 'success' });
|
|
|
+ this.closeCityPicker();
|
|
|
+ // 重置选择器,下次打开重新加载
|
|
|
+ this.selectedPathway = [];
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.msg || '修改失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('修改城市失败:', error);
|
|
|
+ uni.showToast({ title: '网络错误', icon: 'none' });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -403,36 +496,48 @@ page {
|
|
|
.popup-title-text { font-size: 32rpx; font-weight: bold; color: #333; }
|
|
|
.popup-btn-confirm { font-size: 28rpx; color: #FF5722; font-weight: bold; }
|
|
|
|
|
|
-.city-tabs {
|
|
|
+/* 级联城市选择器(与我要加入页面一致) */
|
|
|
+.picker-body {
|
|
|
display: flex;
|
|
|
- padding: 20rpx 30rpx;
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
+ height: 500rpx;
|
|
|
}
|
|
|
-.city-tab-item {
|
|
|
- font-size: 28rpx;
|
|
|
- margin-right: 40rpx;
|
|
|
- position: relative;
|
|
|
- padding-bottom: 10rpx;
|
|
|
-}
|
|
|
-.city-tab-item.active { color: #333; }
|
|
|
-.city-tab-item.active-red { color: #FF5722; font-weight: bold; }
|
|
|
-.city-tab-item.active-red::after {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- width: 40rpx;
|
|
|
- height: 4rpx;
|
|
|
- background-color: #FF5722;
|
|
|
- border-radius: 2rpx;
|
|
|
+.timeline-area {
|
|
|
+ width: 240rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-right: 1px solid #eee;
|
|
|
+ overflow-y: auto;
|
|
|
}
|
|
|
-.city-list {
|
|
|
- height: 400rpx;
|
|
|
+.timeline-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16rpx 0;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
}
|
|
|
-.city-item {
|
|
|
- padding: 30rpx;
|
|
|
+.timeline-item.active {
|
|
|
+ color: #FF5722;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+.timeline-dot {
|
|
|
+ width: 16rpx;
|
|
|
+ height: 16rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #ccc;
|
|
|
+ margin-right: 12rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.timeline-item.active .timeline-dot {
|
|
|
+ background: #FF5722;
|
|
|
+}
|
|
|
+.list-area {
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+.list-area .list-item {
|
|
|
+ padding: 24rpx 30rpx;
|
|
|
font-size: 28rpx;
|
|
|
color: #333;
|
|
|
+ border-bottom: 1px solid #f5f5f5;
|
|
|
}
|
|
|
</style>
|