Commit 89352c3f4f2250b55354a4d7044de162c90d5cf8
1 parent
7399632e
feat: 新增地址,切换请求地址url,修改请求逻辑,修改u-tabs组件
Showing
17 changed files
with
727 additions
and
564 deletions
garbage-removal/.env.preview
garbage-removal/.env.production
garbage-removal/src/App.vue
| 1 | -<script> | |
| 2 | -export default { | |
| 3 | - onLaunch: function () { | |
| 4 | - console.log('App Launch') | |
| 5 | - }, | |
| 6 | - onShow: function () { | |
| 7 | - console.log('App Show') | |
| 8 | - }, | |
| 9 | - onHide: function () { | |
| 10 | - console.log('App Hide') | |
| 11 | - }, | |
| 12 | -} | |
| 1 | +<script setup> | |
| 2 | +import { onLaunch } from "@dcloudio/uni-app"; | |
| 3 | +import { useMainStore } from "./stores/index.js"; | |
| 4 | +import { setRequestToken } from "./utils/request/request.js"; | |
| 5 | +const store = useMainStore(); | |
| 6 | + | |
| 7 | +onLaunch(async () => { | |
| 8 | + console.log("store::==>", store); | |
| 9 | + if (store.token) { | |
| 10 | + setRequestToken(store.token); | |
| 11 | + // store.userInfo = (await getUserInfo()).data.data; | |
| 12 | + uni.switchTab({ | |
| 13 | + url: "/pages/home/index", | |
| 14 | + }); | |
| 15 | + } else { | |
| 16 | + uni.reLaunch({ | |
| 17 | + url: "/pages/login/index", | |
| 18 | + }); | |
| 19 | + } | |
| 20 | +}); | |
| 13 | 21 | </script> |
| 14 | 22 | |
| 15 | 23 | <style lang="scss"> |
| ... | ... | @@ -17,18 +25,6 @@ export default { |
| 17 | 25 | @import "./uview-plus/index.scss"; |
| 18 | 26 | @import "./static/icon/iconfont/iconfont.css"; |
| 19 | 27 | |
| 20 | -html { | |
| 21 | - font-family: '黑体'; | |
| 22 | -} | |
| 23 | - | |
| 24 | -.body { | |
| 25 | - font-family: '黑体'; | |
| 26 | -} | |
| 27 | - | |
| 28 | -.container { | |
| 29 | - font-family: '黑体'; | |
| 30 | -} | |
| 31 | - | |
| 32 | 28 | page { |
| 33 | 29 | box-sizing: border-box; |
| 34 | 30 | min-height: 100%; | ... | ... |
garbage-removal/src/apis/address.js
0 → 100644
| 1 | + | |
| 2 | +import { request } from "@/utils/request"; | |
| 3 | +/** | |
| 4 | + * @method 新增用户地址 | |
| 5 | + */ | |
| 6 | +export async function addAddress( params, config) { | |
| 7 | + return await request.post( | |
| 8 | + `/user/save/address`, | |
| 9 | + params, | |
| 10 | + config | |
| 11 | + ); | |
| 12 | +} | |
| 13 | +/** | |
| 14 | + * @method 获取用户地址 | |
| 15 | + */ | |
| 16 | +export async function queryAddress( type) { | |
| 17 | + return await request.get( | |
| 18 | + `/user/query/address/${type}` | |
| 19 | + ); | |
| 20 | +} | |
| 21 | +/** | |
| 22 | + * @method 编辑用户地址 | |
| 23 | + */ | |
| 24 | +export async function updateAddress( params,config) { | |
| 25 | + return await request.post( | |
| 26 | + `/user/update/address`, | |
| 27 | + params, | |
| 28 | + config | |
| 29 | + ); | |
| 30 | +} | |
| 31 | +/** | |
| 32 | + * @method 编辑用户地址 | |
| 33 | + */ | |
| 34 | +export async function deleteAddress( id) { | |
| 35 | + return await request.delete( | |
| 36 | + `/user/delete/address/${id}` | |
| 37 | + ); | |
| 38 | +} | ... | ... |
garbage-removal/src/apis/company.js
0 → 100644
garbage-removal/src/apis/index.js deleted
100644 → 0
| 1 | -export * from "./user"; |
garbage-removal/src/apis/user.js
| ... | ... | @@ -6,10 +6,7 @@ const prefix = "/user"; |
| 6 | 6 | /** |
| 7 | 7 | * @method 用户登录 |
| 8 | 8 | */ |
| 9 | -export async function userLogin( | |
| 10 | - params, | |
| 11 | - config | |
| 12 | -) { | |
| 9 | +export async function userLogin( params, config) { | |
| 13 | 10 | return await request.post( |
| 14 | 11 | `${prefix}/login`, |
| 15 | 12 | params, |
| ... | ... | @@ -27,6 +24,8 @@ export async function getUserInfo(config) { |
| 27 | 24 | /** |
| 28 | 25 | * @method 发送验证码 |
| 29 | 26 | */ |
| 30 | -export function sendCode() { | |
| 31 | - return request.get(`${prefix}/sendCode`); | |
| 27 | +export async function sendCode(params) { | |
| 28 | + return await request.get( | |
| 29 | + `${prefix}/send/verify?tel=${params}` | |
| 30 | + ); | |
| 32 | 31 | } | ... | ... |
garbage-removal/src/pages.json
| ... | ... | @@ -8,6 +8,17 @@ |
| 8 | 8 | }, |
| 9 | 9 | "pages": [ |
| 10 | 10 | { |
| 11 | + "path": "pages/login/index", | |
| 12 | + "style": { | |
| 13 | + "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录" | |
| 14 | + } | |
| 15 | + },{ | |
| 16 | + "path": "pages/login/code", | |
| 17 | + "style": { | |
| 18 | + "navigationBarTitleText": "输入验证码" | |
| 19 | + } | |
| 20 | + }, | |
| 21 | + { | |
| 11 | 22 | "path": "pages/home/index", |
| 12 | 23 | "style": { |
| 13 | 24 | "navigationBarTitleText": "", |
| ... | ... | @@ -40,13 +51,17 @@ |
| 40 | 51 | { |
| 41 | 52 | "path": "pages/home/address/index", |
| 42 | 53 | "style": { |
| 43 | - "navigationBarTitleText": "清运地址" | |
| 54 | + "navigationBarTitleText": "清运地址", | |
| 55 | + "navigationBarTextStyle":"white", | |
| 56 | + "navigationBarBackgroundColor":"#53c21d" | |
| 44 | 57 | } |
| 45 | 58 | }, |
| 46 | 59 | { |
| 47 | 60 | "path": "pages/home/address/addSite", |
| 48 | 61 | "style": { |
| 49 | - "navigationBarTitleText": "清运地址" | |
| 62 | + "navigationBarTitleText": "清运地址", | |
| 63 | + "navigationBarTextStyle":"white", | |
| 64 | + "navigationBarBackgroundColor":"#53c21d" | |
| 50 | 65 | } |
| 51 | 66 | },{ |
| 52 | 67 | "path": "pages/order/index", |
| ... | ... | @@ -60,17 +75,6 @@ |
| 60 | 75 | "style": { |
| 61 | 76 | "navigationBarTitleText": "" |
| 62 | 77 | } |
| 63 | - }, | |
| 64 | - { | |
| 65 | - "path": "pages/login/index", | |
| 66 | - "style": { | |
| 67 | - "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录" | |
| 68 | - } | |
| 69 | - },{ | |
| 70 | - "path": "pages/login/code", | |
| 71 | - "style": { | |
| 72 | - "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录" | |
| 73 | - } | |
| 74 | 78 | } |
| 75 | 79 | ], |
| 76 | 80 | "tabBar": { | ... | ... |
garbage-removal/src/pages/home/address/addSite.vue
| ... | ... | @@ -9,8 +9,11 @@ |
| 9 | 9 | placeholder="省市区县、乡镇等"></u--input> |
| 10 | 10 | </u-form-item> |
| 11 | 11 | <u-form-item :required="true" label="详细地址" prop="addressDetail" borderBottom> |
| 12 | - <u--input border="none" type="text" v-model="addressInfo.addressDetail" placeholder-class="line" | |
| 13 | - placeholder="请填写收货人姓名详细地址"></u--input> | |
| 12 | + <view class="wrap-from-container-address-details" style="display: flex;"> | |
| 13 | + <u--input border="none" type="text" v-model="addressInfo.addressDetail" placeholder-class="line" | |
| 14 | + placeholder="请填写详细地址"></u--input> | |
| 15 | + <u-icon name="map" size="40" @click="chooseAddressDetail"></u-icon> | |
| 16 | + </view> | |
| 14 | 17 | </u-form-item> |
| 15 | 18 | <u-form-item :required="true" label="联系人" prop="contactPerson" borderBottom> |
| 16 | 19 | <u--input border="none" type="text" v-model="addressInfo.contactPerson" placeholder-class="line" |
| ... | ... | @@ -25,24 +28,31 @@ |
| 25 | 28 | <view class="bottom"> |
| 26 | 29 | <view class="default"> |
| 27 | 30 | <view class="left"> |
| 28 | - <view class="set">设置默认地址</view> | |
| 31 | + <view class="set">当前选中地址</view> | |
| 29 | 32 | </view> |
| 30 | 33 | <view class="right"> |
| 31 | 34 | <u-switch v-model="addressInfo.defaultFlag" size="40" activeColor="#a9e08f"></u-switch> |
| 32 | 35 | </view> |
| 33 | 36 | </view> |
| 34 | 37 | </view> |
| 35 | - <view class="submit-button" @click="submit"> | |
| 36 | - <view class="add">新增地址</view> | |
| 38 | + <view class="submit-button"> | |
| 39 | + <view v-if="addFlag" @click="submit" class="add">新增地址</view> | |
| 40 | + <view v-else class="update-box"> | |
| 41 | + <view class="del" @click="handleDeleteClick">删除地址</view> | |
| 42 | + <view class="update" @click="handleUpdateClick">保存地址</view> | |
| 43 | + </view> | |
| 37 | 44 | </view> |
| 38 | 45 | </view> |
| 39 | 46 | </template> |
| 40 | 47 | |
| 41 | 48 | <script setup> |
| 49 | +import { addAddress, deleteAddress, updateAddress } from '@/apis/address.js'; | |
| 50 | +import { onLoad } from '@dcloudio/uni-app'; | |
| 42 | 51 | import { getCurrentInstance, onMounted, reactive, ref } from 'vue'; |
| 43 | 52 | import citySelect from './citySelect/u-city-select.vue'; |
| 44 | 53 | const { proxy } = getCurrentInstance(); |
| 45 | 54 | const cityPikerShowFlag = ref(false) |
| 55 | +const addFlag = ref(true) | |
| 46 | 56 | const addressInfo = reactive({ |
| 47 | 57 | addressArea: "", |
| 48 | 58 | addressDetail: "", |
| ... | ... | @@ -84,23 +94,105 @@ const rules = reactive({ |
| 84 | 94 | trigger: ['change', 'blur'], |
| 85 | 95 | }] |
| 86 | 96 | }) |
| 97 | + | |
| 87 | 98 | const showRegionPicker = () => { |
| 88 | 99 | cityPikerShowFlag.value = true; |
| 89 | 100 | } |
| 101 | + | |
| 90 | 102 | const handleCityChange = (e) => { |
| 91 | 103 | addressInfo.addressArea = e.province.label + '-' + e.city.label + '-' + e.area.label; |
| 92 | 104 | } |
| 105 | + | |
| 106 | +const handleDeleteClick = () => { | |
| 107 | + uni.showModal({ | |
| 108 | + title: '', | |
| 109 | + content: '是否确认删除这个地址', | |
| 110 | + success: function (res) { | |
| 111 | + if (res.confirm) { | |
| 112 | + deleteAddress(addressInfo.garAddressId).then(res => { | |
| 113 | + if (res.data.success) { | |
| 114 | + uni.$u.toast(res.data.msg) | |
| 115 | + jumpAddressList() | |
| 116 | + } | |
| 117 | + }) | |
| 118 | + } else if (res.cancel) { | |
| 119 | + } | |
| 120 | + } | |
| 121 | + }); | |
| 122 | + | |
| 123 | +} | |
| 124 | + | |
| 125 | +const handleUpdateClick = () => { | |
| 126 | + updateAddress(addressInfo).then(res => { | |
| 127 | + console.log(res); | |
| 128 | + uni.$u.toast(res.data.msg) | |
| 129 | + if (res.data.success) { | |
| 130 | + setTimeout(() => { | |
| 131 | + jumpAddressList(); | |
| 132 | + }, 200); | |
| 133 | + } | |
| 134 | + }) | |
| 135 | +} | |
| 136 | + | |
| 137 | +const jumpAddressList = () => { | |
| 138 | + reset(); | |
| 139 | + uni.$u.route({ | |
| 140 | + type: 'navigateBack', | |
| 141 | + url: `pages/home/address/index`, | |
| 142 | + }) | |
| 143 | +} | |
| 144 | + | |
| 93 | 145 | const submit = () => { |
| 94 | - console.log(addressInfo); | |
| 95 | 146 | proxy.$refs.addressFrom.validate().then(res => { |
| 96 | - uni.$u.toast('新增成功') | |
| 147 | + addAddress(addressInfo).then(res => { | |
| 148 | + uni.$u.toast(res.data.msg) | |
| 149 | + if (res.data.success) { | |
| 150 | + setTimeout(() => { | |
| 151 | + jumpAddressList(); | |
| 152 | + }, 200); | |
| 153 | + } | |
| 154 | + }) | |
| 97 | 155 | }).catch(errors => { |
| 98 | - uni.$u.toast('校验失败') | |
| 156 | + uni.$u.toast('请填写正确信息!') | |
| 99 | 157 | }) |
| 100 | 158 | } |
| 159 | +/** | |
| 160 | + * 打开地图选择地址 | |
| 161 | + */ | |
| 162 | +const chooseAddressDetail = () => { | |
| 163 | + console.log("sss"); | |
| 164 | + uni.chooseLocation({ | |
| 165 | + success: function (res) { | |
| 166 | + addressInfo.addressDetail = res.address + res.name; | |
| 167 | + } | |
| 168 | + }); | |
| 169 | +} | |
| 170 | + | |
| 101 | 171 | onMounted(() => { |
| 102 | 172 | proxy.$refs.addressFrom.setRules(rules) |
| 103 | 173 | }) |
| 174 | + | |
| 175 | +onLoad((options) => { | |
| 176 | + if (options.addressObj) { | |
| 177 | + let addressObj = JSON.parse(options.addressObj); | |
| 178 | + addressInfo.addressArea = addressObj.garUserAddress; | |
| 179 | + addressInfo.contactPerson = addressObj.garUserContactName; | |
| 180 | + addressInfo.contactIphoneNumber = addressObj.garUserContactTel; | |
| 181 | + addressInfo.defaultFlag = addressObj.garUserDefault == 1 ? true : false; | |
| 182 | + addressInfo.addressDetail = addressObj.garRemark; | |
| 183 | + addressInfo.garAddressId = addressObj.garAddressId | |
| 184 | + addFlag.value = false; | |
| 185 | + } | |
| 186 | +}) | |
| 187 | +const reset = () => { | |
| 188 | + addressInfo.addressArea = '' | |
| 189 | + addressInfo.contactPerson = '' | |
| 190 | + addressInfo.contactIphoneNumber = '' | |
| 191 | + addressInfo.defaultFlag = false | |
| 192 | + addressInfo.addressDetail = '' | |
| 193 | + addressInfo.garAddressId = '' | |
| 194 | + addFlag.value = true | |
| 195 | +} | |
| 104 | 196 | </script> |
| 105 | 197 | |
| 106 | 198 | <style lang="scss" scoped> |
| ... | ... | @@ -110,7 +202,7 @@ onMounted(() => { |
| 110 | 202 | // background-color: $u-info-light; |
| 111 | 203 | height: 100%; |
| 112 | 204 | width: 100%; |
| 113 | - background: linear-gradient(to bottom, $u-success-disabled, $u-info-light, $u-info-light, $u-info-light); | |
| 205 | + background: linear-gradient(to bottom, $u-success-dark, $u-info-light, $u-info-light, $u-info-light); | |
| 114 | 206 | |
| 115 | 207 | .wrap-from-container { |
| 116 | 208 | width: 100%; |
| ... | ... | @@ -148,21 +240,51 @@ onMounted(() => { |
| 148 | 240 | |
| 149 | 241 | .submit-button { |
| 150 | 242 | display: flex; |
| 151 | - justify-content: space-around; | |
| 152 | 243 | width: 600rpx; |
| 153 | 244 | line-height: 100rpx; |
| 154 | 245 | position: absolute; |
| 155 | 246 | bottom: 30rpx; |
| 156 | 247 | left: 80rpx; |
| 157 | - background-color: #a9e08f; | |
| 158 | - border-radius: 60rpx; | |
| 159 | 248 | font-size: 30rpx; |
| 249 | + color: #ffffff; | |
| 160 | 250 | |
| 161 | 251 | .add { |
| 252 | + background-color: #a9e08f; | |
| 253 | + border-radius: 60rpx; | |
| 254 | + width: 100%; | |
| 162 | 255 | display: flex; |
| 163 | 256 | align-items: center; |
| 164 | - color: #ffffff; | |
| 257 | + justify-content: center; | |
| 258 | + } | |
| 259 | + | |
| 260 | + .update-box { | |
| 261 | + width: 100%; | |
| 262 | + display: flex; | |
| 263 | + justify-content: space-around; | |
| 264 | + | |
| 265 | + .del { | |
| 266 | + width: 100%; | |
| 267 | + display: flex; | |
| 268 | + align-items: center; | |
| 269 | + justify-content: center; | |
| 270 | + border-radius: 60rpx; | |
| 271 | + background-color: $u-error-disabled; | |
| 272 | + margin-right: 30rpx; | |
| 273 | + } | |
| 274 | + | |
| 275 | + .update { | |
| 276 | + width: 100%; | |
| 277 | + background-color: $u-success-dark; | |
| 278 | + border-radius: 60rpx; | |
| 279 | + display: flex; | |
| 280 | + align-items: center; | |
| 281 | + justify-content: center; | |
| 282 | + } | |
| 283 | + | |
| 284 | + | |
| 165 | 285 | } |
| 166 | 286 | } |
| 287 | + | |
| 288 | + | |
| 167 | 289 | } |
| 168 | 290 | </style> | ... | ... |
garbage-removal/src/pages/home/address/index.vue
| ... | ... | @@ -2,16 +2,18 @@ |
| 2 | 2 | <view class="address-container"> |
| 3 | 3 | <view class="address-box"> |
| 4 | 4 | <view class="item" v-for="(res, index) in siteList" :key="res.id"> |
| 5 | - <view class="top"> | |
| 6 | - <view class="name">{{ res.name }}</view> | |
| 7 | - <view class="phone">{{ res.phone }}</view> | |
| 5 | + <view class="top" @click="handleClickChangeCurrentAddress(res)"> | |
| 6 | + <view class="name">{{ res.garUserContactName }}</view> | |
| 7 | + <view class="phone">{{ res.garUserContactTel }}</view> | |
| 8 | 8 | <view class="tag"> |
| 9 | - <text v-if="res.tag" :class="{ red: res.tag == '默认' }">{{ res.tag }}</text> | |
| 9 | + <text v-if="res.garUserDefault == 1" :class="{ red: res.garUserDefault == 1 }"> | |
| 10 | + {{ res.garUserDefault == 1 ? "当前选中" : "" }} | |
| 11 | + </text> | |
| 10 | 12 | </view> |
| 11 | 13 | </view> |
| 12 | 14 | <view class="bottom"> |
| 13 | - 广东省深圳市宝安区 自由路66号 | |
| 14 | - <u-icon name="edit-pen" :size="40" color="#999999"></u-icon> | |
| 15 | + {{ res.garUserAddress + res.garRemark }} | |
| 16 | + <u-icon name="edit-pen" @click="handleUpdateAddress(res)" :size="40" color="#999999"></u-icon> | |
| 15 | 17 | </view> |
| 16 | 18 | </view> |
| 17 | 19 | |
| ... | ... | @@ -23,68 +25,44 @@ |
| 23 | 25 | </template> |
| 24 | 26 | |
| 25 | 27 | <script setup> |
| 26 | -import { onLoad } from '@dcloudio/uni-app'; | |
| 28 | +import { queryAddress, updateAddress } from "@/apis/address.js"; | |
| 29 | +import { onShow } from '@dcloudio/uni-app'; | |
| 27 | 30 | import { ref } from 'vue'; |
| 28 | 31 | const siteList = ref([]); |
| 32 | + | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * 初始话数据 | |
| 36 | + */ | |
| 29 | 37 | const getData = () => { |
| 30 | - siteList.value = [ | |
| 31 | - { | |
| 32 | - id: 1, | |
| 33 | - name: '游X', | |
| 34 | - phone: '183****5523', | |
| 35 | - tag: '默认', | |
| 36 | - site: '广东省深圳市宝安区 自由路66号' | |
| 37 | - }, | |
| 38 | - { | |
| 39 | - id: 2, | |
| 40 | - name: '李XX', | |
| 41 | - phone: '183****5555', | |
| 42 | - tag: '', | |
| 43 | - site: '广东省深圳市宝安区 翻身路xx号' | |
| 44 | - }, | |
| 45 | - { | |
| 46 | - id: 3, | |
| 47 | - name: '王YY', | |
| 48 | - phone: '153****5555', | |
| 49 | - tag: '', | |
| 50 | - site: '广东省深圳市宝安区 平安路13号' | |
| 51 | - }, | |
| 52 | - { | |
| 53 | - id: 4, | |
| 54 | - name: '王YY', | |
| 55 | - phone: '153****5555', | |
| 56 | - tag: '', | |
| 57 | - site: '广东省深圳市宝安区 平安路13号' | |
| 58 | - }, | |
| 59 | - { | |
| 60 | - id: 5, | |
| 61 | - name: '王YY', | |
| 62 | - phone: '153****5555', | |
| 63 | - tag: '', | |
| 64 | - site: '广东省深圳市宝安区 平安路13号' | |
| 65 | - }, | |
| 66 | - { | |
| 67 | - id: 6, | |
| 68 | - name: '王YY', | |
| 69 | - phone: '153****5555', | |
| 70 | - tag: '', | |
| 71 | - site: '广东省深圳市宝安区 平安路13号' | |
| 72 | - }, | |
| 73 | - { | |
| 74 | - id: 7, | |
| 75 | - name: '王YY', | |
| 76 | - phone: '153****5555', | |
| 77 | - tag: '', | |
| 78 | - site: '广东省深圳市宝安区 平安路13号' | |
| 79 | - }, | |
| 80 | - { | |
| 81 | - id: 8, | |
| 82 | - name: '王YY', | |
| 83 | - phone: '153****5555', | |
| 84 | - tag: '', | |
| 85 | - site: '广东省深圳市宝安区 平安路13号' | |
| 86 | - } | |
| 87 | - ]; | |
| 38 | + queryAddress("ALL").then(res => { | |
| 39 | + siteList.value = res.data.data; | |
| 40 | + }) | |
| 41 | +} | |
| 42 | + | |
| 43 | +// 编辑地址 | |
| 44 | +const handleUpdateAddress = (res) => { | |
| 45 | + let addressObj = JSON.stringify(res); | |
| 46 | + uni.navigateTo({ | |
| 47 | + url: `/pages/home/address/addSite?addressObj=${addressObj}` | |
| 48 | + }); | |
| 49 | +} | |
| 50 | + | |
| 51 | +const handleClickChangeCurrentAddress = (res) => { | |
| 52 | + if (res.garUserDefault == 1) { | |
| 53 | + return | |
| 54 | + } | |
| 55 | + updateAddress({ | |
| 56 | + addressArea: res.garUserAddress, | |
| 57 | + contactPerson: res.garUserContactName, | |
| 58 | + contactIphoneNumber: res.garUserContactTel, | |
| 59 | + defaultFlag: true, | |
| 60 | + addressDetail: res.garRemark, | |
| 61 | + garAddressId: res.garAddressId | |
| 62 | + }).then(res => { | |
| 63 | + getData(); | |
| 64 | + uni.$u.toast(res.data.msg) | |
| 65 | + }) | |
| 88 | 66 | } |
| 89 | 67 | |
| 90 | 68 | const toAddSite = () => { |
| ... | ... | @@ -92,8 +70,9 @@ const toAddSite = () => { |
| 92 | 70 | url: '/pages/home/address/addSite' |
| 93 | 71 | }); |
| 94 | 72 | } |
| 95 | -onLoad(() => { | |
| 73 | +onShow(() => { | |
| 96 | 74 | getData(); |
| 75 | + | |
| 97 | 76 | }) |
| 98 | 77 | </script> |
| 99 | 78 | |
| ... | ... | @@ -101,7 +80,7 @@ onLoad(() => { |
| 101 | 80 | .address-container { |
| 102 | 81 | height: 100%; |
| 103 | 82 | width: 100%; |
| 104 | - background: linear-gradient(to bottom, $u-success-disabled, $u-info-light, $u-info-light, $u-info-light); | |
| 83 | + background: linear-gradient(to bottom, $u-success-dark, $u-info-light, $u-info-light, $u-info-light, $u-info-light, $u-info-light, #ffffff); | |
| 105 | 84 | padding: 20rpx; |
| 106 | 85 | box-sizing: border-box; |
| 107 | 86 | display: flex; |
| ... | ... | @@ -138,7 +117,7 @@ onLoad(() => { |
| 138 | 117 | |
| 139 | 118 | text { |
| 140 | 119 | display: block; |
| 141 | - width: 60rpx; | |
| 120 | + width: auto; | |
| 142 | 121 | height: 34rpx; |
| 143 | 122 | line-height: 34rpx; |
| 144 | 123 | color: #ffffff; | ... | ... |
garbage-removal/src/pages/home/index.vue
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | }" class="top-address"> |
| 10 | 10 | <view class="address-icon-image"><u-icon name="map" color="#fff" size="28"></u-icon></view> |
| 11 | 11 | <view class="address-text" @click="handleAddressInfo"> |
| 12 | - 浙江省-宁波市-海曙区-鼓楼街道南站东xxxx | |
| 12 | + {{ userAddress ? userAddress : "请设置清运地址" }} | |
| 13 | 13 | </view> |
| 14 | 14 | <view class="address-icon-label"> |
| 15 | 15 | <u-icon name="arrow-right" color="#fff" size="28"></u-icon> |
| ... | ... | @@ -88,7 +88,9 @@ |
| 88 | 88 | </template> |
| 89 | 89 | |
| 90 | 90 | <script setup > |
| 91 | -import { onLoad } from '@dcloudio/uni-app'; | |
| 91 | +import { queryAddress } from '@/apis/address.js'; | |
| 92 | +import { queryDisposalSiteList } from '@/apis/company.js'; | |
| 93 | +import { onLoad, onShow } from '@dcloudio/uni-app'; | |
| 92 | 94 | import { ref } from 'vue'; |
| 93 | 95 | // 定义最大积分 |
| 94 | 96 | let maxScore = 5 |
| ... | ... | @@ -104,6 +106,7 @@ const swiperImageList = ref([{ |
| 104 | 106 | image: 'https://cdn.uviewui.com/uview/swiper/swiper3.png', |
| 105 | 107 | }]) |
| 106 | 108 | |
| 109 | +const userAddress = ref() | |
| 107 | 110 | |
| 108 | 111 | |
| 109 | 112 | // 信息指南 |
| ... | ... | @@ -133,26 +136,26 @@ const companyList = ref([ |
| 133 | 136 | remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', |
| 134 | 137 | tel: '18980249130', |
| 135 | 138 | } |
| 136 | - // , { | |
| 137 | - // companyId: '2', | |
| 138 | - // score: 4, | |
| 139 | - // image: 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png', | |
| 140 | - // companyName: '宁波垃圾回收公司', | |
| 141 | - // startPrice: '500', | |
| 142 | - // cleanNumber: '1996', | |
| 143 | - // remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', | |
| 144 | - // tel: '18980249130', | |
| 145 | - // }, | |
| 146 | - // { | |
| 147 | - // companyId: '3', | |
| 148 | - // score: 4, | |
| 149 | - // image: 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png', | |
| 150 | - // companyName: '宁波垃圾回收公司', | |
| 151 | - // startPrice: '500', | |
| 152 | - // cleanNumber: '1996', | |
| 153 | - // remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', | |
| 154 | - // tel: '18980249130', | |
| 155 | - // }, | |
| 139 | + , { | |
| 140 | + companyId: '2', | |
| 141 | + score: 4, | |
| 142 | + image: 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png', | |
| 143 | + companyName: '宁波垃圾回收公司', | |
| 144 | + startPrice: '500', | |
| 145 | + cleanNumber: '1996', | |
| 146 | + remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', | |
| 147 | + tel: '18980249130', | |
| 148 | + }, | |
| 149 | + { | |
| 150 | + companyId: '3', | |
| 151 | + score: 4, | |
| 152 | + image: 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png', | |
| 153 | + companyName: '宁波垃圾回收公司', | |
| 154 | + startPrice: '500', | |
| 155 | + cleanNumber: '1996', | |
| 156 | + remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', | |
| 157 | + tel: '18980249130', | |
| 158 | + }, | |
| 156 | 159 | // { |
| 157 | 160 | // companyId: '1', |
| 158 | 161 | // score: 4, |
| ... | ... | @@ -215,29 +218,36 @@ const handleSearchClick = () => { |
| 215 | 218 | * 计算胶囊高度 |
| 216 | 219 | */ |
| 217 | 220 | onLoad(() => { |
| 218 | - console.log("计算胶囊高度"); | |
| 221 | + // 积分初始化 | |
| 222 | + for (let index = 0; index < maxScore; index++) { | |
| 223 | + maxStar.value.push(index); | |
| 224 | + } | |
| 225 | + | |
| 226 | + // 获取胶囊按钮信息(width、height、top等) | |
| 219 | 227 | try { |
| 220 | - if (topMargin.value) { | |
| 221 | - console.log("计算完毕"); | |
| 222 | - } | |
| 223 | 228 | const { height, top } = uni.getMenuButtonBoundingClientRect(); |
| 224 | 229 | topMargin.value = top + "px"; |
| 225 | - // 获取胶囊按钮信息(width、height、top等) | |
| 226 | 230 | lightHeight.value = height + 'px' |
| 227 | - console.log("计算完毕"); | |
| 228 | 231 | } catch (error) { |
| 229 | 232 | topMargin.value = "60rpx"; |
| 230 | 233 | musicheadHeight.value = "40rpx" |
| 231 | 234 | console.log("There is no menu because the current app is not a small program"); |
| 232 | 235 | } |
| 233 | - // 初始化评分 | |
| 236 | +}) | |
| 237 | +onShow(() => { | |
| 238 | + // 初始化数据 | |
| 234 | 239 | initData() |
| 235 | 240 | }) |
| 236 | - | |
| 237 | 241 | const initData = () => { |
| 238 | - for (let index = 0; index < maxScore; index++) { | |
| 239 | - maxStar.value.push(index); | |
| 240 | - } | |
| 242 | + userAddress.value = null; | |
| 243 | + // 查询用户当前地址 | |
| 244 | + queryAddress('CURRENT').then(res => { | |
| 245 | + userAddress.value = res.data.data[0].garUserAddress + res.data.data[0].garRemark | |
| 246 | + }) | |
| 247 | + // 查询公司信息 | |
| 248 | + queryDisposalSiteList().then(res => { | |
| 249 | + console.log("company====>", res); | |
| 250 | + }) | |
| 241 | 251 | } |
| 242 | 252 | </script> |
| 243 | 253 | |
| ... | ... | @@ -284,6 +294,7 @@ const initData = () => { |
| 284 | 294 | width: 525rpx; |
| 285 | 295 | display: flex; |
| 286 | 296 | align-items: center; |
| 297 | + padding-left: 20rpx; | |
| 287 | 298 | color: white; |
| 288 | 299 | font-size: 30rpx; |
| 289 | 300 | font-family: '圆体', '黑体'; |
| ... | ... | @@ -395,16 +406,16 @@ const initData = () => { |
| 395 | 406 | } |
| 396 | 407 | |
| 397 | 408 | .company-list-content { |
| 398 | - flex: 1; | |
| 409 | + flex: 1 0 auto; | |
| 410 | + height: 0; | |
| 399 | 411 | box-sizing: border-box; |
| 400 | 412 | margin-top: 20rpx; |
| 401 | 413 | flex-shrink: 0; |
| 402 | - height: 0; | |
| 403 | 414 | margin-bottom: 20rpx; |
| 404 | 415 | width: 100%; |
| 405 | 416 | |
| 406 | 417 | .company-list-content-box { |
| 407 | - height: 99%; | |
| 418 | + height: 100%; | |
| 408 | 419 | width: 100%; |
| 409 | 420 | box-sizing: border-box; |
| 410 | 421 | overflow: scroll; | ... | ... |
garbage-removal/src/pages/login/code.vue
| ... | ... | @@ -14,77 +14,94 @@ |
| 14 | 14 | </view> |
| 15 | 15 | </template> |
| 16 | 16 | |
| 17 | -<script> | |
| 18 | -export default { | |
| 19 | - data() { | |
| 20 | - return { | |
| 21 | - verifyFlag: false, | |
| 22 | - iphoneNumber: "", | |
| 23 | - startIphoneNumber: "", | |
| 24 | - maxlength: 4, | |
| 25 | - value: '', | |
| 26 | - second: 10, | |
| 27 | - show: false | |
| 28 | - }; | |
| 29 | - }, | |
| 30 | - computed: {}, | |
| 31 | - onLoad(options) { | |
| 32 | - this.iphoneNumber = options.iphoneNumber; | |
| 33 | - this.startIphoneNumber = this.handleIphoneNumber("" + options.iphoneNumber); | |
| 34 | - this.getCaptcha(this.iphoneNumber) | |
| 35 | - let interval = setInterval(() => { | |
| 36 | - this.second--; | |
| 37 | - if (this.second <= 0) { | |
| 38 | - this.show = true; | |
| 39 | - if (this.value.length != 4) { | |
| 40 | - this.verifyFlag = true; | |
| 41 | - } | |
| 42 | - clearInterval(interval); | |
| 43 | - } | |
| 44 | - }, 1000); | |
| 45 | - }, | |
| 46 | - methods: { | |
| 47 | - handleIphoneNumber(tel) { | |
| 48 | - return tel.replace(tel.substring(3, 7), "****"); | |
| 49 | - }, | |
| 50 | - getCaptcha(iphoneNumber) { | |
| 51 | - console.log("获取验证码:", iphoneNumber); | |
| 52 | - }, | |
| 53 | - // 收不到验证码选择时的选择 | |
| 54 | - noCaptcha() { | |
| 55 | - uni.showActionSheet({ | |
| 56 | - itemList: ['重新获取验证码'], | |
| 57 | - success: function (res) { | |
| 58 | - this.getCaptcha(this.iphoneNumber) | |
| 59 | - }, | |
| 60 | - fail: function (res) { | |
| 61 | - | |
| 62 | - } | |
| 63 | - }); | |
| 64 | - }, | |
| 65 | - // 校验验证码 | |
| 66 | - checkVerifyNum(code) { | |
| 17 | +<script setup> | |
| 18 | +import { sendCode, userLogin } from "@/apis/user.js"; | |
| 19 | +import { useMainStore } from '@/stores/index.js'; | |
| 20 | +import { setRequestToken } from '@/utils/request/request.js'; | |
| 21 | +import { onLoad } from "@dcloudio/uni-app"; | |
| 22 | +import { ref } from "vue"; | |
| 23 | +const store = useMainStore(); | |
| 24 | +const verifyFlag = ref(false) | |
| 25 | +const iphoneNumber = ref("") | |
| 26 | +const startIphoneNumber = ref("") | |
| 27 | +const maxlength = ref(4) | |
| 28 | +const value = ref("") | |
| 29 | +const second = ref(10); | |
| 30 | +const show = ref(false) | |
| 67 | 31 | |
| 32 | +onLoad((options) => { | |
| 33 | + iphoneNumber.value = options.iphoneNumber; | |
| 34 | + startIphoneNumber.value = handleIphoneNumber("" + options.iphoneNumber); | |
| 35 | + getCaptcha(iphoneNumber.value) | |
| 36 | + let interval = setInterval(() => { | |
| 37 | + second.value--; | |
| 38 | + if (second.value <= 0) { | |
| 39 | + show.value = true | |
| 40 | + clearInterval(interval); | |
| 41 | + } | |
| 42 | + }, 1000); | |
| 43 | +}) | |
| 44 | + | |
| 45 | +const handleIphoneNumber = (tel) => { | |
| 46 | + return tel.replace(tel.substring(3, 7), "****"); | |
| 47 | +} | |
| 48 | + | |
| 49 | +const getCaptcha = (iphoneNumber) => { | |
| 50 | + value.value = '' | |
| 51 | + second.value = 10 | |
| 52 | + show.value = false; | |
| 53 | + let interval = setInterval(() => { | |
| 54 | + second.value--; | |
| 55 | + if (second.value <= 0) { | |
| 56 | + show.value = true | |
| 57 | + clearInterval(interval); | |
| 58 | + } | |
| 59 | + }, 1000); | |
| 60 | + sendCode(iphoneNumber).then(res => { | |
| 61 | + console.log(res); | |
| 62 | + }) | |
| 63 | +} | |
| 64 | +// 收不到验证码选择时的选择 | |
| 65 | +const noCaptcha = () => { | |
| 66 | + uni.showActionSheet({ | |
| 67 | + itemList: ['重新获取验证码'], | |
| 68 | + success: function (res) { | |
| 69 | + getCaptcha(iphoneNumber.value) | |
| 68 | 70 | }, |
| 69 | - // change事件侦听 | |
| 70 | - change(value) { | |
| 71 | - if (value.length != 4) { | |
| 72 | - this.verifyFlag = true; | |
| 73 | - } | |
| 74 | - }, | |
| 75 | - // 输入完验证码最后一位执行 | |
| 76 | - finish(value) { | |
| 77 | - if (value.length == 4) { | |
| 78 | - // TODO 到首页 | |
| 79 | - this.verifyFlag = false; | |
| 80 | - this.$u.route({ | |
| 81 | - type: "switchTab", | |
| 82 | - url: `pages/home/index`, | |
| 83 | - }) | |
| 84 | - } | |
| 71 | + fail: function (res) { | |
| 72 | + | |
| 85 | 73 | } |
| 74 | + }); | |
| 75 | +} | |
| 76 | + | |
| 77 | +// 校验验证码 | |
| 78 | +const checkVerifyNum = (code) => { | |
| 79 | + userLogin({ loginType: 0, tel: iphoneNumber.value, code: code }).then(res => { | |
| 80 | + // 登录成功 | |
| 81 | + if (res.data.success) { | |
| 82 | + verifyFlag.value = false; | |
| 83 | + setRequestToken(res.data.data) | |
| 84 | + store.token = res.data.data | |
| 85 | + uni.$u.route({ | |
| 86 | + type: "switchTab", | |
| 87 | + url: `pages/home/index`, | |
| 88 | + }) | |
| 89 | + } else { | |
| 90 | + verifyFlag.value = true; | |
| 91 | + } | |
| 92 | + }) | |
| 93 | +} | |
| 94 | + | |
| 95 | +// change事件侦听 | |
| 96 | +const change = (value) => { | |
| 97 | +} | |
| 98 | + | |
| 99 | +// 输入完验证码最后一位执行 | |
| 100 | +const finish = (value) => { | |
| 101 | + if (value.length == 4) { | |
| 102 | + checkVerifyNum(value); | |
| 86 | 103 | } |
| 87 | -}; | |
| 104 | +} | |
| 88 | 105 | </script> |
| 89 | 106 | |
| 90 | 107 | <style lang="scss" scoped> | ... | ... |
garbage-removal/src/pages/login/index.vue
| ... | ... | @@ -12,9 +12,12 @@ |
| 12 | 12 | </view> |
| 13 | 13 | <view class="buttom"> |
| 14 | 14 | <view class="loginType"> |
| 15 | - <view class="wechat item" @click="handleWeixinLogin"> | |
| 16 | - <view class="icon"><u-icon size="40" name="weixin-fill" color="rgb(83,194,64)"></u-icon></view> | |
| 17 | - 微信 | |
| 15 | + <view class="wechat item"> | |
| 16 | + <button class="box" open-type="getPhoneNumber" @getphonenumber="handleWeixinLogin"> | |
| 17 | + <view class="icon"><u-icon size="60" name="weixin-fill" color="rgb(83,194,64)"></u-icon> | |
| 18 | + </view> | |
| 19 | + 微信登录 | |
| 20 | + </button> | |
| 18 | 21 | </view> |
| 19 | 22 | </view> |
| 20 | 23 | <view class="hint"> |
| ... | ... | @@ -27,10 +30,11 @@ |
| 27 | 30 | </template> |
| 28 | 31 | |
| 29 | 32 | <script> |
| 33 | +import { userLogin } from "@/apis/user.js"; | |
| 30 | 34 | export default { |
| 31 | 35 | data() { |
| 32 | 36 | return { |
| 33 | - tel: '' | |
| 37 | + tel: '18980249160' | |
| 34 | 38 | } |
| 35 | 39 | }, |
| 36 | 40 | computed: { |
| ... | ... | @@ -63,18 +67,17 @@ export default { |
| 63 | 67 | handleUserAgreement() { |
| 64 | 68 | console.log("user click agreement"); |
| 65 | 69 | }, |
| 66 | - handleWeixinLogin() { | |
| 70 | + handleWeixinLogin(wxInfo) { | |
| 67 | 71 | uni.login({ |
| 68 | 72 | provider: 'weixin', |
| 69 | - success: (res) => { | |
| 70 | - this.code = res.code; | |
| 71 | - console.log('code', res.code); | |
| 72 | - if (res.errMsg == 'login:ok') { | |
| 73 | - //TODO 获取code 携带code参数调用后端接口} | |
| 74 | - | |
| 75 | - } | |
| 73 | + success: res => { | |
| 74 | + userLogin({ loginType: type, encryptedData: wxInfo.detail.encryptedData, iv: wxInfo.detail.iv, wxCode: res.code }) | |
| 75 | + .then(res => { | |
| 76 | + console.log(res); | |
| 77 | + }) | |
| 76 | 78 | } |
| 77 | - }) | |
| 79 | + | |
| 80 | + }); | |
| 78 | 81 | } |
| 79 | 82 | } |
| 80 | 83 | } |
| ... | ... | @@ -110,7 +113,7 @@ export default { |
| 110 | 113 | |
| 111 | 114 | .getCaptcha { |
| 112 | 115 | background-color: #5ac725; |
| 113 | - color: $u-tips-color; | |
| 116 | + color: #ffffff; | |
| 114 | 117 | border: none; |
| 115 | 118 | font-size: 30rpx; |
| 116 | 119 | padding: 12rpx 0; |
| ... | ... | @@ -135,12 +138,27 @@ export default { |
| 135 | 138 | justify-content: center; |
| 136 | 139 | |
| 137 | 140 | .item { |
| 138 | - display: flex; | |
| 139 | - flex-direction: column; | |
| 140 | - align-items: center; | |
| 141 | - color: $u-content-color; | |
| 142 | - font-size: 28rpx; | |
| 141 | + .box { | |
| 142 | + display: flex; | |
| 143 | + flex-direction: column; | |
| 144 | + align-items: center; | |
| 145 | + color: $u-content-color; | |
| 146 | + justify-content: center; | |
| 147 | + font-size: 28rpx; | |
| 148 | + background-color: #ffffff00; | |
| 149 | + border-radius: 0 !important; | |
| 150 | + border: 0 solid #ffffff00 !important; | |
| 151 | + padding: 0 !important; | |
| 152 | + margin: 0 !important; | |
| 153 | + | |
| 154 | + &::after { | |
| 155 | + border: none; | |
| 156 | + } | |
| 157 | + | |
| 158 | + } | |
| 159 | + | |
| 143 | 160 | } |
| 161 | + | |
| 144 | 162 | } |
| 145 | 163 | |
| 146 | 164 | .hint { | ... | ... |
garbage-removal/src/pages/order/swiper-list-item/index.vue
| 1 | 1 | <template> |
| 2 | 2 | <view class="content-container"> |
| 3 | - <z-paging ref="paging" v-model="dataList" @query="queryList"> | |
| 3 | + <z-paging ref="paging" :fixed="false" v-model="dataList" @query="queryList"> | |
| 4 | 4 | <empty-view slot:empty></empty-view> |
| 5 | - <view class="item" v-for="(item, index) in dataList"> | |
| 6 | - <view class="item-title">{{ item }}</view> | |
| 5 | + <view class="content-container-item-box" v-for="(item, index) in dataList"> | |
| 6 | + <view class="content-container-item-box-title">{{ item }}</view> | |
| 7 | 7 | </view> |
| 8 | 8 | </z-paging> |
| 9 | 9 | </view> |
| ... | ... | @@ -23,6 +23,7 @@ const props = defineProps({ |
| 23 | 23 | const paging = ref(null) |
| 24 | 24 | const dataList = ref([]) |
| 25 | 25 | const count = ref(0) |
| 26 | +const timer = ref() | |
| 26 | 27 | const queryList = (pageNo, pageSize) => { |
| 27 | 28 | //这里的pageNo和pageSize会自动计算好,直接传给服务器即可 |
| 28 | 29 | //这里的请求只是演示,请替换成自己的项目的网络请求,并在网络请求回调中通过paging.value.complete(请求回来的数组)将请求结果传给z-paging |
| ... | ... | @@ -33,12 +34,13 @@ const queryList = (pageNo, pageSize) => { |
| 33 | 34 | return |
| 34 | 35 | } |
| 35 | 36 | if (++count.value < 3) { |
| 36 | - | |
| 37 | + clearTimeout(timer.value) | |
| 38 | + timer.value = setTimeout(() => { | |
| 39 | + console.log("hhhh"); | |
| 40 | + paging.value.complete([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); | |
| 41 | + }, 500); | |
| 37 | 42 | } |
| 38 | - setInterval(() => { | |
| 39 | - paging.value.complete([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); | |
| 40 | - }, 500); | |
| 41 | - paging.value.complete([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); | |
| 43 | + | |
| 42 | 44 | // }).catch(res => { |
| 43 | 45 | // //如果请求失败写paging.value.complete(false),会自动展示错误页面 |
| 44 | 46 | // //注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理 | ... | ... |
garbage-removal/src/stores/main.js
garbage-removal/src/utils/request/request.js
| ... | ... | @@ -54,34 +54,32 @@ const instance = axios.create({ |
| 54 | 54 | }); |
| 55 | 55 | // 请求拦截器 |
| 56 | 56 | instance.interceptors.request.use((config) => { |
| 57 | - console.log("请求拦截器", config); | |
| 58 | - | |
| 59 | 57 | return config; |
| 60 | 58 | }); |
| 61 | 59 | // 响应拦截器 |
| 62 | 60 | instance.interceptors.response.use((response) => { |
| 63 | - console.log("响应拦截器", response); | |
| 64 | 61 | if (response.data.code != 200) { |
| 65 | 62 | uni.showToast({ |
| 66 | 63 | title: response.data.message, |
| 67 | 64 | icon: "none", |
| 68 | 65 | }); |
| 69 | 66 | if (response.data.code == 401) { |
| 70 | - uni.navigateTo({ | |
| 71 | - url: "/pages/login/index", | |
| 72 | - }); | |
| 67 | + reSetLoginStatus(); | |
| 73 | 68 | } |
| 74 | 69 | } |
| 75 | 70 | return response; |
| 76 | -},(error) => { | |
| 71 | +}, (error) => { | |
| 77 | 72 | if (error.response.status) { |
| 78 | 73 | switch (error.response.status) { |
| 79 | - case 401: | |
| 74 | + case 401: | |
| 75 | + case 403: | |
| 76 | + setRequestToken(null); | |
| 80 | 77 | break; |
| 81 | 78 | default: |
| 82 | 79 | break; |
| 83 | 80 | } |
| 84 | - } | |
| 81 | + } | |
| 82 | + uni.$u.toast("网络波动请再试~") | |
| 85 | 83 | return Promise.reject(error) |
| 86 | 84 | }); |
| 87 | 85 | export default instance; |
| ... | ... | @@ -89,3 +87,10 @@ export default instance; |
| 89 | 87 | export function setRequestToken(token) { |
| 90 | 88 | instance.defaults.headers.common["Authorization"] = `${token}`; |
| 91 | 89 | } |
| 90 | + | |
| 91 | +const reSetLoginStatus = () => { | |
| 92 | + uni.navigateTo({ | |
| 93 | + type: "reLaunch", | |
| 94 | + url: "/pages/login/index", | |
| 95 | + }); | |
| 96 | +} | ... | ... |
garbage-removal/src/uview-plus/components/u-tabs/u-tabs.vue
| ... | ... | @@ -3,34 +3,16 @@ |
| 3 | 3 | <view class="u-tabs__wrapper"> |
| 4 | 4 | <slot name="left" /> |
| 5 | 5 | <view class="u-tabs__wrapper__scroll-view-wrapper"> |
| 6 | - <scroll-view | |
| 7 | - :scroll-x="scrollable" | |
| 8 | - :scroll-left="scrollLeft" | |
| 9 | - scroll-with-animation | |
| 10 | - class="u-tabs__wrapper__scroll-view" | |
| 11 | - :show-scrollbar="false" | |
| 12 | - ref="u-tabs__wrapper__scroll-view" | |
| 13 | - > | |
| 14 | - <view | |
| 15 | - class="u-tabs__wrapper__nav" | |
| 16 | - ref="u-tabs__wrapper__nav" | |
| 17 | - > | |
| 18 | - <view | |
| 19 | - class="u-tabs__wrapper__nav__item" | |
| 20 | - v-for="(item, index) in list" | |
| 21 | - :key="index" | |
| 22 | - @tap="clickHandler(item, index)" | |
| 23 | - :ref="`u-tabs__wrapper__nav__item-${index}`" | |
| 24 | - :style="[$u.addStyle(itemStyle), {flex: scrollable ? '' : 1}]" | |
| 25 | - :class="[`u-tabs__wrapper__nav__item-${index}`, item.disabled && 'u-tabs__wrapper__nav__item--disabled']" | |
| 26 | - > | |
| 27 | - <text | |
| 28 | - :class="[item.disabled && 'u-tabs__wrapper__nav__item__text--disabled']" | |
| 29 | - class="u-tabs__wrapper__nav__item__text" | |
| 30 | - :style="[textStyle(index)]" | |
| 31 | - >{{ item[keyName] }}</text> | |
| 32 | - <u-badge | |
| 33 | - :show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))" | |
| 6 | + <scroll-view :scroll-x="scrollable" :scroll-left="scrollLeft" scroll-with-animation | |
| 7 | + class="u-tabs__wrapper__scroll-view" :show-scrollbar="false" ref="u-tabs__wrapper__scroll-view"> | |
| 8 | + <view class="u-tabs__wrapper__nav" ref="u-tabs__wrapper__nav"> | |
| 9 | + <view class="u-tabs__wrapper__nav__item" v-for="(item, index) in list" :key="index" | |
| 10 | + @tap="clickHandler(item, index)" :ref="`u-tabs__wrapper__nav__item-${index}`" | |
| 11 | + :style="[$u.addStyle(itemStyle), { flex: scrollable ? '' : 1 }]" | |
| 12 | + :class="[`u-tabs__wrapper__nav__item-${index}`, item.disabled && 'u-tabs__wrapper__nav__item--disabled']"> | |
| 13 | + <text :class="[item.disabled && 'u-tabs__wrapper__nav__item__text--disabled']" | |
| 14 | + class="u-tabs__wrapper__nav__item__text" :style="[textStyle(index)]">{{ item[keyName] }}</text> | |
| 15 | + <u-badge :show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))" | |
| 34 | 16 | :isDot="item.badge && item.badge.isDot || propsBadge.isDot" |
| 35 | 17 | :value="item.badge && item.badge.value || propsBadge.value" |
| 36 | 18 | :max="item.badge && item.badge.max || propsBadge.max" |
| ... | ... | @@ -41,35 +23,26 @@ |
| 41 | 23 | :shape="item.badge && item.badge.shape || propsBadge.shape" |
| 42 | 24 | :numberType="item.badge && item.badge.numberType || propsBadge.numberType" |
| 43 | 25 | :inverted="item.badge && item.badge.inverted || propsBadge.inverted" |
| 44 | - customStyle="margin-left: 4px;" | |
| 45 | - ></u-badge> | |
| 26 | + customStyle="margin-left: 4px;"></u-badge> | |
| 46 | 27 | </view> |
| 47 | 28 | <!-- #ifdef APP-NVUE --> |
| 48 | - <view | |
| 49 | - class="u-tabs__wrapper__nav__line" | |
| 50 | - ref="u-tabs__wrapper__nav__line" | |
| 51 | - :style="[{ | |
| 52 | - width: $u.addUnit(lineWidth), | |
| 53 | - height: $u.addUnit(lineHeight), | |
| 54 | - background: lineColor, | |
| 55 | - backgroundSize: lineBgSize, | |
| 56 | - }]" | |
| 57 | - > | |
| 29 | + <view class="u-tabs__wrapper__nav__line" ref="u-tabs__wrapper__nav__line" :style="[{ | |
| 30 | + width: $u.addUnit(lineWidth), | |
| 31 | + height: $u.addUnit(lineHeight), | |
| 32 | + background: lineColor, | |
| 33 | + backgroundSize: lineBgSize, | |
| 34 | + }]"> | |
| 58 | 35 | </view> |
| 59 | 36 | <!-- #endif --> |
| 60 | 37 | <!-- #ifndef APP-NVUE --> |
| 61 | - <view | |
| 62 | - class="u-tabs__wrapper__nav__line" | |
| 63 | - ref="u-tabs__wrapper__nav__line" | |
| 64 | - :style="[{ | |
| 65 | - width: $u.addUnit(lineWidth), | |
| 66 | - transform: `translate(${lineOffsetLeft}px)`, | |
| 67 | - transitionDuration: `${firstTime ? 0 : duration}ms`, | |
| 68 | - height: $u.addUnit(lineHeight), | |
| 69 | - background: lineColor, | |
| 70 | - backgroundSize: lineBgSize, | |
| 71 | - }]" | |
| 72 | - > | |
| 38 | + <view class="u-tabs__wrapper__nav__line" ref="u-tabs__wrapper__nav__line" :style="[{ | |
| 39 | + width: $u.addUnit(lineWidth), | |
| 40 | + transform: `translate(${lineOffsetLeft}px)`, | |
| 41 | + transitionDuration: `${firstTime ? 0 : duration}ms`, | |
| 42 | + height: $u.addUnit(lineHeight), | |
| 43 | + background: lineColor, | |
| 44 | + backgroundSize: lineBgSize, | |
| 45 | + }]"> | |
| 73 | 46 | </view> |
| 74 | 47 | <!-- #endif --> |
| 75 | 48 | </view> |
| ... | ... | @@ -81,278 +54,268 @@ |
| 81 | 54 | </template> |
| 82 | 55 | |
| 83 | 56 | <script> |
| 84 | - // #ifdef APP-NVUE | |
| 85 | - const animation = uni.requireNativePlugin('animation') | |
| 86 | - const dom = uni.requireNativePlugin('dom') | |
| 87 | - // #endif | |
| 88 | - import props from './props.js'; | |
| 89 | - import mpMixin from '../../libs/mixin/mpMixin.js'; | |
| 90 | - import mixin from '../../libs/mixin/mixin.js'; | |
| 91 | - /** | |
| 92 | - * Tabs 标签 | |
| 93 | - * @description tabs标签组件,在标签多的时候,可以配置为左右滑动,标签少的时候,可以禁止滑动。 该组件的一个特点是配置为滚动模式时,激活的tab会自动移动到组件的中间位置。 | |
| 94 | - * @tutorial https://ijry.github.io/uview-plus/components/tabs.html | |
| 95 | - * @property {String | Number} duration 滑块移动一次所需的时间,单位秒(默认 200 ) | |
| 96 | - * @property {String | Number} swierWidth swiper的宽度(默认 '750rpx' ) | |
| 97 | - * @property {String} keyName 从`list`元素对象中读取的键名(默认 'name' ) | |
| 98 | - * @event {Function(index)} change 标签改变时触发 index: 点击了第几个tab,索引从0开始 | |
| 99 | - * @event {Function(index)} click 点击标签时触发 index: 点击了第几个tab,索引从0开始 | |
| 100 | - * @example <u-tabs :list="list" :is-scroll="false" :current="current" @change="change"></u-tabs> | |
| 101 | - */ | |
| 102 | - export default { | |
| 103 | - name: 'u-tabs', | |
| 104 | - mixins: [mpMixin, mixin, props], | |
| 105 | - data() { | |
| 106 | - return { | |
| 107 | - firstTime: true, | |
| 108 | - scrollLeft: 0, | |
| 109 | - scrollViewWidth: 0, | |
| 110 | - lineOffsetLeft: 0, | |
| 111 | - tabsRect: { | |
| 112 | - left: 0 | |
| 113 | - }, | |
| 114 | - innerCurrent: 0, | |
| 115 | - moving: false, | |
| 57 | +// #ifdef APP-NVUE | |
| 58 | +const animation = uni.requireNativePlugin('animation') | |
| 59 | +const dom = uni.requireNativePlugin('dom') | |
| 60 | +// #endif | |
| 61 | +import mixin from '../../libs/mixin/mixin.js'; | |
| 62 | +import mpMixin from '../../libs/mixin/mpMixin.js'; | |
| 63 | +import props from './props.js'; | |
| 64 | +/** | |
| 65 | + * Tabs 标签 | |
| 66 | + * @description tabs标签组件,在标签多的时候,可以配置为左右滑动,标签少的时候,可以禁止滑动。 该组件的一个特点是配置为滚动模式时,激活的tab会自动移动到组件的中间位置。 | |
| 67 | + * @tutorial https://ijry.github.io/uview-plus/components/tabs.html | |
| 68 | + * @property {String | Number} duration 滑块移动一次所需的时间,单位秒(默认 200 ) | |
| 69 | + * @property {String | Number} swierWidth swiper的宽度(默认 '750rpx' ) | |
| 70 | + * @property {String} keyName 从`list`元素对象中读取的键名(默认 'name' ) | |
| 71 | + * @event {Function(index)} change 标签改变时触发 index: 点击了第几个tab,索引从0开始 | |
| 72 | + * @event {Function(index)} click 点击标签时触发 index: 点击了第几个tab,索引从0开始 | |
| 73 | + * @example <u-tabs :list="list" :is-scroll="false" :current="current" @change="change"></u-tabs> | |
| 74 | + */ | |
| 75 | +export default { | |
| 76 | + name: 'u-tabs', | |
| 77 | + mixins: [mpMixin, mixin, props], | |
| 78 | + data() { | |
| 79 | + return { | |
| 80 | + firstTime: true, | |
| 81 | + scrollLeft: 0, | |
| 82 | + scrollViewWidth: 0, | |
| 83 | + lineOffsetLeft: 0, | |
| 84 | + tabsRect: { | |
| 85 | + left: 0 | |
| 86 | + }, | |
| 87 | + innerCurrent: 0, | |
| 88 | + moving: false, | |
| 89 | + } | |
| 90 | + }, | |
| 91 | + watch: { | |
| 92 | + current: { | |
| 93 | + immediate: true, | |
| 94 | + handler(newValue, oldValue) { | |
| 95 | + // 内外部值不相等时,才尝试移动滑块 | |
| 96 | + if (newValue !== this.innerCurrent) { | |
| 97 | + this.innerCurrent = newValue | |
| 98 | + this.$nextTick(() => { | |
| 99 | + this.resize() | |
| 100 | + }) | |
| 101 | + } | |
| 116 | 102 | } |
| 117 | 103 | }, |
| 118 | - watch: { | |
| 119 | - current: { | |
| 120 | - immediate: true, | |
| 121 | - handler (newValue, oldValue) { | |
| 122 | - // 内外部值不相等时,才尝试移动滑块 | |
| 123 | - if (newValue !== this.innerCurrent) { | |
| 124 | - this.innerCurrent = newValue | |
| 125 | - this.$nextTick(() => { | |
| 126 | - this.resize() | |
| 127 | - }) | |
| 128 | - } | |
| 104 | + // list变化时,重新渲染list各项信息 | |
| 105 | + list() { | |
| 106 | + this.$nextTick(() => { | |
| 107 | + this.resize() | |
| 108 | + }) | |
| 109 | + } | |
| 110 | + }, | |
| 111 | + computed: { | |
| 112 | + textStyle() { | |
| 113 | + return index => { | |
| 114 | + const style = {} | |
| 115 | + // 取当期是否激活的样式 | |
| 116 | + const customeStyle = index === this.innerCurrent ? uni.$u.addStyle(this.activeStyle) : uni.$u | |
| 117 | + .addStyle( | |
| 118 | + this.inactiveStyle) | |
| 119 | + // 如果当前菜单被禁用,则加上对应颜色,需要在此做处理,是因为nvue下,无法在style样式中通过!import覆盖标签的内联样式 | |
| 120 | + if (this.list[index].disabled) { | |
| 121 | + style.color = '#c8c9cc' | |
| 129 | 122 | } |
| 130 | - }, | |
| 131 | - // list变化时,重新渲染list各项信息 | |
| 132 | - list() { | |
| 133 | - this.$nextTick(() => { | |
| 134 | - this.resize() | |
| 135 | - }) | |
| 123 | + return uni.$u.deepMerge(customeStyle, style) | |
| 136 | 124 | } |
| 137 | 125 | }, |
| 138 | - computed: { | |
| 139 | - textStyle() { | |
| 140 | - return index => { | |
| 141 | - const style = {} | |
| 142 | - // 取当期是否激活的样式 | |
| 143 | - const customeStyle = index === this.innerCurrent ? uni.$u.addStyle(this.activeStyle) : uni.$u | |
| 144 | - .addStyle( | |
| 145 | - this.inactiveStyle) | |
| 146 | - // 如果当前菜单被禁用,则加上对应颜色,需要在此做处理,是因为nvue下,无法在style样式中通过!import覆盖标签的内联样式 | |
| 147 | - if (this.list[index].disabled) { | |
| 148 | - style.color = '#c8c9cc' | |
| 149 | - } | |
| 150 | - return uni.$u.deepMerge(customeStyle, style) | |
| 151 | - } | |
| 152 | - }, | |
| 153 | - propsBadge() { | |
| 154 | - return uni.$u.props.badge | |
| 126 | + propsBadge() { | |
| 127 | + return uni.$u.props.badge | |
| 128 | + } | |
| 129 | + }, | |
| 130 | + async mounted() { | |
| 131 | + this.init() | |
| 132 | + }, | |
| 133 | + emits: ['click', 'change'], | |
| 134 | + methods: { | |
| 135 | + setLineLeft() { | |
| 136 | + const tabItem = this.list[this.innerCurrent]; | |
| 137 | + if (!tabItem) { | |
| 138 | + return; | |
| 139 | + } | |
| 140 | + // 获取滑块该移动的位置 | |
| 141 | + let lineOffsetLeft = this.list | |
| 142 | + .slice(0, this.innerCurrent) | |
| 143 | + .reduce((total, curr) => total + curr.rect.width, 0); | |
| 144 | + // 获取下划线的数值px表示法 | |
| 145 | + const lineWidth = uni.$u.getPx(this.lineWidth); | |
| 146 | + this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2 | |
| 147 | + // #ifdef APP-NVUE | |
| 148 | + // 第一次移动滑块,无需过渡时间 | |
| 149 | + this.animation(this.lineOffsetLeft, this.firstTime ? 0 : parseInt(this.duration)) | |
| 150 | + // #endif | |
| 151 | + | |
| 152 | + // 如果是第一次执行此方法,让滑块在初始化时,瞬间滑动到第一个tab item的中间 | |
| 153 | + // 这里需要一个定时器,因为在非nvue下,是直接通过style绑定过渡时间,需要等其过渡完成后,再设置为false(非第一次移动滑块) | |
| 154 | + if (this.firstTime) { | |
| 155 | + setTimeout(() => { | |
| 156 | + this.firstTime = false | |
| 157 | + }, 10); | |
| 155 | 158 | } |
| 156 | 159 | }, |
| 157 | - async mounted() { | |
| 158 | - this.init() | |
| 160 | + // nvue下设置滑块的位置 | |
| 161 | + animation(x, duration = 0) { | |
| 162 | + // #ifdef APP-NVUE | |
| 163 | + const ref = this.$refs['u-tabs__wrapper__nav__line'] | |
| 164 | + animation.transition(ref, { | |
| 165 | + styles: { | |
| 166 | + transform: `translateX(${x}px)` | |
| 167 | + }, | |
| 168 | + duration | |
| 169 | + }) | |
| 170 | + // #endif | |
| 159 | 171 | }, |
| 160 | - emits: ['click', 'change'], | |
| 161 | - methods: { | |
| 162 | - setLineLeft() { | |
| 163 | - const tabItem = this.list[this.innerCurrent]; | |
| 164 | - if (!tabItem) { | |
| 165 | - return; | |
| 166 | - } | |
| 167 | - // 获取滑块该移动的位置 | |
| 168 | - let lineOffsetLeft = this.list | |
| 169 | - .slice(0, this.innerCurrent) | |
| 170 | - .reduce((total, curr) => total + curr.rect.width, 0); | |
| 171 | - // 获取下划线的数值px表示法 | |
| 172 | - const lineWidth = uni.$u.getPx(this.lineWidth); | |
| 173 | - this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2 | |
| 174 | - // #ifdef APP-NVUE | |
| 175 | - // 第一次移动滑块,无需过渡时间 | |
| 176 | - this.animation(this.lineOffsetLeft, this.firstTime ? 0 : parseInt(this.duration)) | |
| 177 | - // #endif | |
| 178 | - | |
| 179 | - // 如果是第一次执行此方法,让滑块在初始化时,瞬间滑动到第一个tab item的中间 | |
| 180 | - // 这里需要一个定时器,因为在非nvue下,是直接通过style绑定过渡时间,需要等其过渡完成后,再设置为false(非第一次移动滑块) | |
| 181 | - if (this.firstTime) { | |
| 182 | - setTimeout(() => { | |
| 183 | - this.firstTime = false | |
| 184 | - }, 10); | |
| 185 | - } | |
| 186 | - }, | |
| 187 | - // nvue下设置滑块的位置 | |
| 188 | - animation(x, duration = 0) { | |
| 189 | - // #ifdef APP-NVUE | |
| 190 | - const ref = this.$refs['u-tabs__wrapper__nav__line'] | |
| 191 | - animation.transition(ref, { | |
| 192 | - styles: { | |
| 193 | - transform: `translateX(${x}px)` | |
| 194 | - }, | |
| 195 | - duration | |
| 196 | - }) | |
| 197 | - // #endif | |
| 198 | - }, | |
| 199 | - // 点击某一个标签 | |
| 200 | - clickHandler(item, index) { | |
| 201 | - // 因为标签可能为disabled状态,所以click是一定会发出的,但是change事件是需要可用的状态才发出 | |
| 202 | - this.$emit('click', { | |
| 203 | - ...item, | |
| 204 | - index | |
| 205 | - }) | |
| 206 | - // 如果disabled状态,返回 | |
| 207 | - if (item.disabled) return | |
| 208 | - this.innerCurrent = index | |
| 172 | + // 点击某一个标签 | |
| 173 | + clickHandler(item, index) { | |
| 174 | + // 因为标签可能为disabled状态,所以click是一定会发出的,但是change事件是需要可用的状态才发出 | |
| 175 | + this.$emit('click', { | |
| 176 | + ...item, | |
| 177 | + index | |
| 178 | + }) | |
| 179 | + // 如果disabled状态,返回 | |
| 180 | + if (item.disabled) return | |
| 181 | + this.innerCurrent = index | |
| 182 | + this.resize() | |
| 183 | + this.$emit('change', { | |
| 184 | + ...item, | |
| 185 | + index | |
| 186 | + }) | |
| 187 | + }, | |
| 188 | + init() { | |
| 189 | + uni.$u.sleep().then(() => { | |
| 209 | 190 | this.resize() |
| 210 | - this.$emit('change', { | |
| 211 | - ...item, | |
| 212 | - index | |
| 213 | - }) | |
| 214 | - }, | |
| 215 | - init() { | |
| 216 | - uni.$u.sleep().then(() => { | |
| 217 | - this.resize() | |
| 218 | - }) | |
| 219 | - }, | |
| 220 | - setScrollLeft() { | |
| 221 | - // 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息 | |
| 222 | - const tabRect = this.list[this.innerCurrent] | |
| 223 | - // 累加得到当前item到左边的距离 | |
| 224 | - const offsetLeft = this.list | |
| 225 | - .slice(0, this.innerCurrent) | |
| 226 | - .reduce((total, curr) => { | |
| 227 | - return total + curr.rect.width | |
| 228 | - }, 0) | |
| 229 | - // 此处为屏幕宽度 | |
| 230 | - const windowWidth = uni.$u.sys().windowWidth | |
| 231 | - // 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动 | |
| 232 | - let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect | |
| 233 | - .right) / 2 + this.tabsRect.left / 2 | |
| 234 | - // 这里做一个限制,限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度 | |
| 235 | - scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width) | |
| 236 | - this.scrollLeft = Math.max(0, scrollLeft) | |
| 237 | - }, | |
| 238 | - // 获取所有标签的尺寸 | |
| 239 | - resize() { | |
| 240 | - // 如果不存在list,则不处理 | |
| 241 | - if(this.list.length === 0) { | |
| 242 | - return | |
| 243 | - } | |
| 244 | - Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => { | |
| 245 | - this.tabsRect = tabsRect | |
| 246 | - this.scrollViewWidth = 0 | |
| 247 | - itemRect.map((item, index) => { | |
| 248 | - // 计算scroll-view的宽度,这里 | |
| 249 | - this.scrollViewWidth += item.width | |
| 250 | - // 另外计算每一个item的中心点X轴坐标 | |
| 251 | - this.list[index].rect = item | |
| 252 | - }) | |
| 253 | - // 获取了tabs的尺寸之后,设置滑块的位置 | |
| 254 | - this.setLineLeft() | |
| 255 | - this.setScrollLeft() | |
| 256 | - }) | |
| 257 | - }, | |
| 258 | - // 获取导航菜单的尺寸 | |
| 259 | - getTabsRect() { | |
| 260 | - return new Promise(resolve => { | |
| 261 | - this.queryRect('u-tabs__wrapper__scroll-view').then(size => resolve(size)) | |
| 262 | - }) | |
| 263 | - }, | |
| 264 | - // 获取所有标签的尺寸 | |
| 265 | - getAllItemRect() { | |
| 266 | - return new Promise(resolve => { | |
| 267 | - const promiseAllArr = this.list.map((item, index) => this.queryRect( | |
| 268 | - `u-tabs__wrapper__nav__item-${index}`, true)) | |
| 269 | - Promise.all(promiseAllArr).then(sizes => resolve(sizes)) | |
| 270 | - }) | |
| 271 | - }, | |
| 272 | - // 获取各个标签的尺寸 | |
| 273 | - queryRect(el, item) { | |
| 274 | - // #ifndef APP-NVUE | |
| 275 | - // $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://ijry.github.io/uview-plus/js/getRect.html | |
| 276 | - // 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同 | |
| 277 | - return new Promise(resolve => { | |
| 278 | - this.$uGetRect(`.${el}`).then(size => { | |
| 279 | - resolve(size) | |
| 280 | - }) | |
| 191 | + }) | |
| 192 | + }, | |
| 193 | + setScrollLeft() { | |
| 194 | + // 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息 | |
| 195 | + const tabRect = this.list[this.innerCurrent] | |
| 196 | + // 累加得到当前item到左边的距离 | |
| 197 | + const offsetLeft = this.list | |
| 198 | + .slice(0, this.innerCurrent) | |
| 199 | + .reduce((total, curr) => { | |
| 200 | + return total + curr.rect.width | |
| 201 | + }, 0) | |
| 202 | + // 此处为屏幕宽度 | |
| 203 | + const windowWidth = uni.$u.sys().windowWidth | |
| 204 | + // 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动 | |
| 205 | + let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect | |
| 206 | + .right) / 2 + this.tabsRect.left / 2 | |
| 207 | + // 这里做一个限制,限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度 | |
| 208 | + scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width) | |
| 209 | + this.scrollLeft = Math.max(0, scrollLeft) | |
| 210 | + }, | |
| 211 | + // 获取所有标签的尺寸 | |
| 212 | + resize() { | |
| 213 | + // 如果不存在list,则不处理 | |
| 214 | + if (this.list.length === 0) { | |
| 215 | + return | |
| 216 | + } | |
| 217 | + Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => { | |
| 218 | + this.tabsRect = tabsRect | |
| 219 | + this.scrollViewWidth = 0 | |
| 220 | + itemRect.map((item, index) => { | |
| 221 | + // 计算scroll-view的宽度,这里 | |
| 222 | + this.scrollViewWidth += item.width | |
| 223 | + // 另外计算每一个item的中心点X轴坐标 | |
| 224 | + this.list[index].rect = item | |
| 281 | 225 | }) |
| 282 | - // #endif | |
| 283 | - | |
| 284 | - // #ifdef APP-NVUE | |
| 285 | - // nvue下,使用dom模块查询元素高度 | |
| 286 | - // 返回一个promise,让调用此方法的主体能使用then回调 | |
| 287 | - return new Promise(resolve => { | |
| 288 | - dom.getComponentRect(item ? this.$refs[el][0] : this.$refs[el], res => { | |
| 289 | - resolve(res.size) | |
| 290 | - }) | |
| 226 | + // 获取了tabs的尺寸之后,设置滑块的位置 | |
| 227 | + this.setLineLeft() | |
| 228 | + this.setScrollLeft() | |
| 229 | + }) | |
| 230 | + }, | |
| 231 | + // 获取导航菜单的尺寸 | |
| 232 | + getTabsRect() { | |
| 233 | + return new Promise(resolve => { | |
| 234 | + this.queryRect('u-tabs__wrapper__scroll-view').then(size => resolve(size)) | |
| 235 | + }) | |
| 236 | + }, | |
| 237 | + // 获取所有标签的尺寸 | |
| 238 | + getAllItemRect() { | |
| 239 | + return new Promise(resolve => { | |
| 240 | + const promiseAllArr = this.list.map((item, index) => this.queryRect( | |
| 241 | + `u-tabs__wrapper__nav__item-${index}`, true)) | |
| 242 | + Promise.all(promiseAllArr).then(sizes => resolve(sizes)) | |
| 243 | + }) | |
| 244 | + }, | |
| 245 | + // 获取各个标签的尺寸 | |
| 246 | + queryRect(el, item) { | |
| 247 | + // #ifndef APP-NVUE | |
| 248 | + // $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://ijry.github.io/uview-plus/js/getRect.html | |
| 249 | + // 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同 | |
| 250 | + return new Promise(resolve => { | |
| 251 | + this.$uGetRect(`.${el}`).then(size => { | |
| 252 | + resolve(size) | |
| 291 | 253 | }) |
| 292 | - // #endif | |
| 293 | - }, | |
| 254 | + }) | |
| 255 | + // #endif | |
| 294 | 256 | }, |
| 295 | - } | |
| 257 | + }, | |
| 258 | +} | |
| 296 | 259 | </script> |
| 297 | 260 | |
| 298 | 261 | <style lang="scss" scoped> |
| 299 | - @import "../../libs/css/components.scss"; | |
| 262 | +@import "../../libs/css/components.scss"; | |
| 263 | + | |
| 264 | +.u-tabs { | |
| 300 | 265 | |
| 301 | - .u-tabs { | |
| 266 | + &__wrapper { | |
| 267 | + @include flex; | |
| 268 | + align-items: center; | |
| 269 | + | |
| 270 | + &__scroll-view-wrapper { | |
| 271 | + flex: 1; | |
| 272 | + /* #ifndef APP-NVUE */ | |
| 273 | + overflow: auto hidden; | |
| 274 | + /* #endif */ | |
| 275 | + } | |
| 302 | 276 | |
| 303 | - &__wrapper { | |
| 277 | + &__scroll-view { | |
| 304 | 278 | @include flex; |
| 305 | - align-items: center; | |
| 279 | + flex: 1; | |
| 280 | + } | |
| 306 | 281 | |
| 307 | - &__scroll-view-wrapper { | |
| 308 | - flex: 1; | |
| 309 | - /* #ifndef APP-NVUE */ | |
| 310 | - overflow: auto hidden; | |
| 311 | - /* #endif */ | |
| 312 | - } | |
| 282 | + &__nav { | |
| 283 | + @include flex; | |
| 284 | + position: relative; | |
| 313 | 285 | |
| 314 | - &__scroll-view { | |
| 286 | + &__item { | |
| 287 | + padding: 0 11px; | |
| 315 | 288 | @include flex; |
| 316 | - flex: 1; | |
| 317 | - } | |
| 289 | + align-items: center; | |
| 290 | + justify-content: center; | |
| 318 | 291 | |
| 319 | - &__nav { | |
| 320 | - @include flex; | |
| 321 | - position: relative; | |
| 292 | + &--disabled { | |
| 293 | + /* #ifndef APP-NVUE */ | |
| 294 | + cursor: not-allowed; | |
| 295 | + /* #endif */ | |
| 296 | + } | |
| 322 | 297 | |
| 323 | - &__item { | |
| 324 | - padding: 0 11px; | |
| 325 | - @include flex; | |
| 326 | - align-items: center; | |
| 327 | - justify-content: center; | |
| 298 | + &__text { | |
| 299 | + font-size: 15px; | |
| 300 | + color: $u-content-color; | |
| 328 | 301 | |
| 329 | 302 | &--disabled { |
| 330 | - /* #ifndef APP-NVUE */ | |
| 331 | - cursor: not-allowed; | |
| 332 | - /* #endif */ | |
| 333 | - } | |
| 334 | - | |
| 335 | - &__text { | |
| 336 | - font-size: 15px; | |
| 337 | - color: $u-content-color; | |
| 338 | - | |
| 339 | - &--disabled { | |
| 340 | - color: $u-disabled-color !important; | |
| 341 | - } | |
| 303 | + color: $u-disabled-color !important; | |
| 342 | 304 | } |
| 343 | 305 | } |
| 306 | + } | |
| 344 | 307 | |
| 345 | - &__line { | |
| 346 | - height: 3px; | |
| 347 | - background: $u-primary; | |
| 348 | - width: 30px; | |
| 349 | - position: absolute; | |
| 350 | - bottom: 2px; | |
| 351 | - border-radius: 100px; | |
| 352 | - transition-property: transform; | |
| 353 | - transition-duration: 300ms; | |
| 354 | - } | |
| 308 | + &__line { | |
| 309 | + height: 3px; | |
| 310 | + background: $u-primary; | |
| 311 | + width: 30px; | |
| 312 | + position: absolute; | |
| 313 | + bottom: 2px; | |
| 314 | + border-radius: 100px; | |
| 315 | + transition-property: transform; | |
| 316 | + transition-duration: 300ms; | |
| 355 | 317 | } |
| 356 | 318 | } |
| 357 | 319 | } |
| 320 | +} | |
| 358 | 321 | </style> | ... | ... |