Commit 89352c3f4f2250b55354a4d7044de162c90d5cf8

Authored by guzijian
1 parent 7399632e

feat: 新增地址,切换请求地址url,修改请求逻辑,修改u-tabs组件

garbage-removal/.env.preview
1 -VITE_BASE_URL=http://localhost:8820 1 +VITE_BASE_URL=http://localhost:8080/workflow
2 2
3 -VITE_STOMP_URL=http://localhost:8860/ws 3 +VITE_STOMP_URL=http://localhost:8080/ws
garbage-removal/.env.production
1 -VITE_BASE_URL=http://1.14.107.94:8820  
2 -VITE_STOMP_URL=http://localhost:8860/ws 1 +# VITE_BASE_URL=http://1.14.107.94:8820
  2 +# VITE_STOMP_URL=http://localhost:8860/ws
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 </script> 21 </script>
14 22
15 <style lang="scss"> 23 <style lang="scss">
@@ -17,18 +25,6 @@ export default { @@ -17,18 +25,6 @@ export default {
17 @import "./uview-plus/index.scss"; 25 @import "./uview-plus/index.scss";
18 @import "./static/icon/iconfont/iconfont.css"; 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 page { 28 page {
33 box-sizing: border-box; 29 box-sizing: border-box;
34 min-height: 100%; 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
  1 +import { request } from "@/utils/request";
  2 +
  3 +/**
  4 + * @method 编辑用户地址
  5 + */
  6 +export async function queryDisposalSiteList() {
  7 + return await request.get(
  8 + `/enterprise/list`
  9 + );
  10 +}
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 = &quot;/user&quot;; @@ -6,10 +6,7 @@ const prefix = &quot;/user&quot;;
6 /** 6 /**
7 * @method 用户登录 7 * @method 用户登录
8 */ 8 */
9 -export async function userLogin(  
10 - params,  
11 - config  
12 -) { 9 +export async function userLogin( params, config) {
13 return await request.post( 10 return await request.post(
14 `${prefix}/login`, 11 `${prefix}/login`,
15 params, 12 params,
@@ -27,6 +24,8 @@ export async function getUserInfo(config) { @@ -27,6 +24,8 @@ export async function getUserInfo(config) {
27 /** 24 /**
28 * @method 发送验证码 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,6 +8,17 @@
8 }, 8 },
9 "pages": [ 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 "path": "pages/home/index", 22 "path": "pages/home/index",
12 "style": { 23 "style": {
13 "navigationBarTitleText": "", 24 "navigationBarTitleText": "",
@@ -40,13 +51,17 @@ @@ -40,13 +51,17 @@
40 { 51 {
41 "path": "pages/home/address/index", 52 "path": "pages/home/address/index",
42 "style": { 53 "style": {
43 - "navigationBarTitleText": "清运地址" 54 + "navigationBarTitleText": "清运地址",
  55 + "navigationBarTextStyle":"white",
  56 + "navigationBarBackgroundColor":"#53c21d"
44 } 57 }
45 }, 58 },
46 { 59 {
47 "path": "pages/home/address/addSite", 60 "path": "pages/home/address/addSite",
48 "style": { 61 "style": {
49 - "navigationBarTitleText": "清运地址" 62 + "navigationBarTitleText": "清运地址",
  63 + "navigationBarTextStyle":"white",
  64 + "navigationBarBackgroundColor":"#53c21d"
50 } 65 }
51 },{ 66 },{
52 "path": "pages/order/index", 67 "path": "pages/order/index",
@@ -60,17 +75,6 @@ @@ -60,17 +75,6 @@
60 "style": { 75 "style": {
61 "navigationBarTitleText": "" 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 "tabBar": { 80 "tabBar": {
garbage-removal/src/pages/home/address/addSite.vue
@@ -9,8 +9,11 @@ @@ -9,8 +9,11 @@
9 placeholder="省市区县、乡镇等"></u--input> 9 placeholder="省市区县、乡镇等"></u--input>
10 </u-form-item> 10 </u-form-item>
11 <u-form-item :required="true" label="详细地址" prop="addressDetail" borderBottom> 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 </u-form-item> 17 </u-form-item>
15 <u-form-item :required="true" label="联系人" prop="contactPerson" borderBottom> 18 <u-form-item :required="true" label="联系人" prop="contactPerson" borderBottom>
16 <u--input border="none" type="text" v-model="addressInfo.contactPerson" placeholder-class="line" 19 <u--input border="none" type="text" v-model="addressInfo.contactPerson" placeholder-class="line"
@@ -25,24 +28,31 @@ @@ -25,24 +28,31 @@
25 <view class="bottom"> 28 <view class="bottom">
26 <view class="default"> 29 <view class="default">
27 <view class="left"> 30 <view class="left">
28 - <view class="set">设置默认地址</view> 31 + <view class="set">当前选中地址</view>
29 </view> 32 </view>
30 <view class="right"> 33 <view class="right">
31 <u-switch v-model="addressInfo.defaultFlag" size="40" activeColor="#a9e08f"></u-switch> 34 <u-switch v-model="addressInfo.defaultFlag" size="40" activeColor="#a9e08f"></u-switch>
32 </view> 35 </view>
33 </view> 36 </view>
34 </view> 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 </view> 44 </view>
38 </view> 45 </view>
39 </template> 46 </template>
40 47
41 <script setup> 48 <script setup>
  49 +import { addAddress, deleteAddress, updateAddress } from '@/apis/address.js';
  50 +import { onLoad } from '@dcloudio/uni-app';
42 import { getCurrentInstance, onMounted, reactive, ref } from 'vue'; 51 import { getCurrentInstance, onMounted, reactive, ref } from 'vue';
43 import citySelect from './citySelect/u-city-select.vue'; 52 import citySelect from './citySelect/u-city-select.vue';
44 const { proxy } = getCurrentInstance(); 53 const { proxy } = getCurrentInstance();
45 const cityPikerShowFlag = ref(false) 54 const cityPikerShowFlag = ref(false)
  55 +const addFlag = ref(true)
46 const addressInfo = reactive({ 56 const addressInfo = reactive({
47 addressArea: "", 57 addressArea: "",
48 addressDetail: "", 58 addressDetail: "",
@@ -84,23 +94,105 @@ const rules = reactive({ @@ -84,23 +94,105 @@ const rules = reactive({
84 trigger: ['change', 'blur'], 94 trigger: ['change', 'blur'],
85 }] 95 }]
86 }) 96 })
  97 +
87 const showRegionPicker = () => { 98 const showRegionPicker = () => {
88 cityPikerShowFlag.value = true; 99 cityPikerShowFlag.value = true;
89 } 100 }
  101 +
90 const handleCityChange = (e) => { 102 const handleCityChange = (e) => {
91 addressInfo.addressArea = e.province.label + '-' + e.city.label + '-' + e.area.label; 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 const submit = () => { 145 const submit = () => {
94 - console.log(addressInfo);  
95 proxy.$refs.addressFrom.validate().then(res => { 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 }).catch(errors => { 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 onMounted(() => { 171 onMounted(() => {
102 proxy.$refs.addressFrom.setRules(rules) 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 </script> 196 </script>
105 197
106 <style lang="scss" scoped> 198 <style lang="scss" scoped>
@@ -110,7 +202,7 @@ onMounted(() =&gt; { @@ -110,7 +202,7 @@ onMounted(() =&gt; {
110 // background-color: $u-info-light; 202 // background-color: $u-info-light;
111 height: 100%; 203 height: 100%;
112 width: 100%; 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 .wrap-from-container { 207 .wrap-from-container {
116 width: 100%; 208 width: 100%;
@@ -148,21 +240,51 @@ onMounted(() =&gt; { @@ -148,21 +240,51 @@ onMounted(() =&gt; {
148 240
149 .submit-button { 241 .submit-button {
150 display: flex; 242 display: flex;
151 - justify-content: space-around;  
152 width: 600rpx; 243 width: 600rpx;
153 line-height: 100rpx; 244 line-height: 100rpx;
154 position: absolute; 245 position: absolute;
155 bottom: 30rpx; 246 bottom: 30rpx;
156 left: 80rpx; 247 left: 80rpx;
157 - background-color: #a9e08f;  
158 - border-radius: 60rpx;  
159 font-size: 30rpx; 248 font-size: 30rpx;
  249 + color: #ffffff;
160 250
161 .add { 251 .add {
  252 + background-color: #a9e08f;
  253 + border-radius: 60rpx;
  254 + width: 100%;
162 display: flex; 255 display: flex;
163 align-items: center; 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 </style> 290 </style>
garbage-removal/src/pages/home/address/index.vue
@@ -2,16 +2,18 @@ @@ -2,16 +2,18 @@
2 <view class="address-container"> 2 <view class="address-container">
3 <view class="address-box"> 3 <view class="address-box">
4 <view class="item" v-for="(res, index) in siteList" :key="res.id"> 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 <view class="tag"> 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 </view> 12 </view>
11 </view> 13 </view>
12 <view class="bottom"> 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 </view> 17 </view>
16 </view> 18 </view>
17 19
@@ -23,68 +25,44 @@ @@ -23,68 +25,44 @@
23 </template> 25 </template>
24 26
25 <script setup> 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 import { ref } from 'vue'; 30 import { ref } from 'vue';
28 const siteList = ref([]); 31 const siteList = ref([]);
  32 +
  33 +
  34 +/**
  35 + * 初始话数据
  36 + */
29 const getData = () => { 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 const toAddSite = () => { 68 const toAddSite = () => {
@@ -92,8 +70,9 @@ const toAddSite = () =&gt; { @@ -92,8 +70,9 @@ const toAddSite = () =&gt; {
92 url: '/pages/home/address/addSite' 70 url: '/pages/home/address/addSite'
93 }); 71 });
94 } 72 }
95 -onLoad(() => { 73 +onShow(() => {
96 getData(); 74 getData();
  75 +
97 }) 76 })
98 </script> 77 </script>
99 78
@@ -101,7 +80,7 @@ onLoad(() =&gt; { @@ -101,7 +80,7 @@ onLoad(() =&gt; {
101 .address-container { 80 .address-container {
102 height: 100%; 81 height: 100%;
103 width: 100%; 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 padding: 20rpx; 84 padding: 20rpx;
106 box-sizing: border-box; 85 box-sizing: border-box;
107 display: flex; 86 display: flex;
@@ -138,7 +117,7 @@ onLoad(() =&gt; { @@ -138,7 +117,7 @@ onLoad(() =&gt; {
138 117
139 text { 118 text {
140 display: block; 119 display: block;
141 - width: 60rpx; 120 + width: auto;
142 height: 34rpx; 121 height: 34rpx;
143 line-height: 34rpx; 122 line-height: 34rpx;
144 color: #ffffff; 123 color: #ffffff;
garbage-removal/src/pages/home/index.vue
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 }" class="top-address"> 9 }" class="top-address">
10 <view class="address-icon-image"><u-icon name="map" color="#fff" size="28"></u-icon></view> 10 <view class="address-icon-image"><u-icon name="map" color="#fff" size="28"></u-icon></view>
11 <view class="address-text" @click="handleAddressInfo"> 11 <view class="address-text" @click="handleAddressInfo">
12 - 浙江省-宁波市-海曙区-鼓楼街道南站东xxxx 12 + {{ userAddress ? userAddress : "请设置清运地址" }}
13 </view> 13 </view>
14 <view class="address-icon-label"> 14 <view class="address-icon-label">
15 <u-icon name="arrow-right" color="#fff" size="28"></u-icon> 15 <u-icon name="arrow-right" color="#fff" size="28"></u-icon>
@@ -88,7 +88,9 @@ @@ -88,7 +88,9 @@
88 </template> 88 </template>
89 89
90 <script setup > 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 import { ref } from 'vue'; 94 import { ref } from 'vue';
93 // 定义最大积分 95 // 定义最大积分
94 let maxScore = 5 96 let maxScore = 5
@@ -104,6 +106,7 @@ const swiperImageList = ref([{ @@ -104,6 +106,7 @@ const swiperImageList = ref([{
104 image: 'https://cdn.uviewui.com/uview/swiper/swiper3.png', 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,26 +136,26 @@ const companyList = ref([
133 remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。', 136 remark: '我司专业拆除清运,装修大件垃圾的环保科技企业。',
134 tel: '18980249130', 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 // companyId: '1', 160 // companyId: '1',
158 // score: 4, 161 // score: 4,
@@ -215,29 +218,36 @@ const handleSearchClick = () =&gt; { @@ -215,29 +218,36 @@ const handleSearchClick = () =&gt; {
215 * 计算胶囊高度 218 * 计算胶囊高度
216 */ 219 */
217 onLoad(() => { 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 try { 227 try {
220 - if (topMargin.value) {  
221 - console.log("计算完毕");  
222 - }  
223 const { height, top } = uni.getMenuButtonBoundingClientRect(); 228 const { height, top } = uni.getMenuButtonBoundingClientRect();
224 topMargin.value = top + "px"; 229 topMargin.value = top + "px";
225 - // 获取胶囊按钮信息(width、height、top等)  
226 lightHeight.value = height + 'px' 230 lightHeight.value = height + 'px'
227 - console.log("计算完毕");  
228 } catch (error) { 231 } catch (error) {
229 topMargin.value = "60rpx"; 232 topMargin.value = "60rpx";
230 musicheadHeight.value = "40rpx" 233 musicheadHeight.value = "40rpx"
231 console.log("There is no menu because the current app is not a small program"); 234 console.log("There is no menu because the current app is not a small program");
232 } 235 }
233 - // 初始化评分 236 +})
  237 +onShow(() => {
  238 + // 初始化数据
234 initData() 239 initData()
235 }) 240 })
236 -  
237 const initData = () => { 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 </script> 252 </script>
243 253
@@ -284,6 +294,7 @@ const initData = () =&gt; { @@ -284,6 +294,7 @@ const initData = () =&gt; {
284 width: 525rpx; 294 width: 525rpx;
285 display: flex; 295 display: flex;
286 align-items: center; 296 align-items: center;
  297 + padding-left: 20rpx;
287 color: white; 298 color: white;
288 font-size: 30rpx; 299 font-size: 30rpx;
289 font-family: '圆体', '黑体'; 300 font-family: '圆体', '黑体';
@@ -395,16 +406,16 @@ const initData = () =&gt; { @@ -395,16 +406,16 @@ const initData = () =&gt; {
395 } 406 }
396 407
397 .company-list-content { 408 .company-list-content {
398 - flex: 1; 409 + flex: 1 0 auto;
  410 + height: 0;
399 box-sizing: border-box; 411 box-sizing: border-box;
400 margin-top: 20rpx; 412 margin-top: 20rpx;
401 flex-shrink: 0; 413 flex-shrink: 0;
402 - height: 0;  
403 margin-bottom: 20rpx; 414 margin-bottom: 20rpx;
404 width: 100%; 415 width: 100%;
405 416
406 .company-list-content-box { 417 .company-list-content-box {
407 - height: 99%; 418 + height: 100%;
408 width: 100%; 419 width: 100%;
409 box-sizing: border-box; 420 box-sizing: border-box;
410 overflow: scroll; 421 overflow: scroll;
garbage-removal/src/pages/login/code.vue
@@ -14,77 +14,94 @@ @@ -14,77 +14,94 @@
14 </view> 14 </view>
15 </template> 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 </script> 105 </script>
89 106
90 <style lang="scss" scoped> 107 <style lang="scss" scoped>
garbage-removal/src/pages/login/index.vue
@@ -12,9 +12,12 @@ @@ -12,9 +12,12 @@
12 </view> 12 </view>
13 <view class="buttom"> 13 <view class="buttom">
14 <view class="loginType"> 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 </view> 21 </view>
19 </view> 22 </view>
20 <view class="hint"> 23 <view class="hint">
@@ -27,10 +30,11 @@ @@ -27,10 +30,11 @@
27 </template> 30 </template>
28 31
29 <script> 32 <script>
  33 +import { userLogin } from "@/apis/user.js";
30 export default { 34 export default {
31 data() { 35 data() {
32 return { 36 return {
33 - tel: '' 37 + tel: '18980249160'
34 } 38 }
35 }, 39 },
36 computed: { 40 computed: {
@@ -63,18 +67,17 @@ export default { @@ -63,18 +67,17 @@ export default {
63 handleUserAgreement() { 67 handleUserAgreement() {
64 console.log("user click agreement"); 68 console.log("user click agreement");
65 }, 69 },
66 - handleWeixinLogin() { 70 + handleWeixinLogin(wxInfo) {
67 uni.login({ 71 uni.login({
68 provider: 'weixin', 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,7 +113,7 @@ export default {
110 113
111 .getCaptcha { 114 .getCaptcha {
112 background-color: #5ac725; 115 background-color: #5ac725;
113 - color: $u-tips-color; 116 + color: #ffffff;
114 border: none; 117 border: none;
115 font-size: 30rpx; 118 font-size: 30rpx;
116 padding: 12rpx 0; 119 padding: 12rpx 0;
@@ -135,12 +138,27 @@ export default { @@ -135,12 +138,27 @@ export default {
135 justify-content: center; 138 justify-content: center;
136 139
137 .item { 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 .hint { 164 .hint {
garbage-removal/src/pages/order/swiper-list-item/index.vue
1 <template> 1 <template>
2 <view class="content-container"> 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 <empty-view slot:empty></empty-view> 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 </view> 7 </view>
8 </z-paging> 8 </z-paging>
9 </view> 9 </view>
@@ -23,6 +23,7 @@ const props = defineProps({ @@ -23,6 +23,7 @@ const props = defineProps({
23 const paging = ref(null) 23 const paging = ref(null)
24 const dataList = ref([]) 24 const dataList = ref([])
25 const count = ref(0) 25 const count = ref(0)
  26 +const timer = ref()
26 const queryList = (pageNo, pageSize) => { 27 const queryList = (pageNo, pageSize) => {
27 //这里的pageNo和pageSize会自动计算好,直接传给服务器即可 28 //这里的pageNo和pageSize会自动计算好,直接传给服务器即可
28 //这里的请求只是演示,请替换成自己的项目的网络请求,并在网络请求回调中通过paging.value.complete(请求回来的数组)将请求结果传给z-paging 29 //这里的请求只是演示,请替换成自己的项目的网络请求,并在网络请求回调中通过paging.value.complete(请求回来的数组)将请求结果传给z-paging
@@ -33,12 +34,13 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -33,12 +34,13 @@ const queryList = (pageNo, pageSize) =&gt; {
33 return 34 return
34 } 35 }
35 if (++count.value < 3) { 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 // }).catch(res => { 44 // }).catch(res => {
43 // //如果请求失败写paging.value.complete(false),会自动展示错误页面 45 // //如果请求失败写paging.value.complete(false),会自动展示错误页面
44 // //注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理 46 // //注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
garbage-removal/src/stores/main.js
@@ -12,7 +12,7 @@ export const useMainStore = defineStore( @@ -12,7 +12,7 @@ export const useMainStore = defineStore(
12 persist: { 12 persist: {
13 enabled: true, 13 enabled: true,
14 H5Storage: localStorage, 14 H5Storage: localStorage,
15 - // 调整为兼容多端的API 15 + // 调整为兼容多端的API
16 storage: { 16 storage: {
17 setItem(key, value) { 17 setItem(key, value) {
18 uni.setStorageSync(key, value) 18 uni.setStorageSync(key, value)
garbage-removal/src/utils/request/request.js
@@ -54,34 +54,32 @@ const instance = axios.create({ @@ -54,34 +54,32 @@ const instance = axios.create({
54 }); 54 });
55 // 请求拦截器 55 // 请求拦截器
56 instance.interceptors.request.use((config) => { 56 instance.interceptors.request.use((config) => {
57 - console.log("请求拦截器", config);  
58 -  
59 return config; 57 return config;
60 }); 58 });
61 // 响应拦截器 59 // 响应拦截器
62 instance.interceptors.response.use((response) => { 60 instance.interceptors.response.use((response) => {
63 - console.log("响应拦截器", response);  
64 if (response.data.code != 200) { 61 if (response.data.code != 200) {
65 uni.showToast({ 62 uni.showToast({
66 title: response.data.message, 63 title: response.data.message,
67 icon: "none", 64 icon: "none",
68 }); 65 });
69 if (response.data.code == 401) { 66 if (response.data.code == 401) {
70 - uni.navigateTo({  
71 - url: "/pages/login/index",  
72 - }); 67 + reSetLoginStatus();
73 } 68 }
74 } 69 }
75 return response; 70 return response;
76 -},(error) => { 71 +}, (error) => {
77 if (error.response.status) { 72 if (error.response.status) {
78 switch (error.response.status) { 73 switch (error.response.status) {
79 - case 401: 74 + case 401:
  75 + case 403:
  76 + setRequestToken(null);
80 break; 77 break;
81 default: 78 default:
82 break; 79 break;
83 } 80 }
84 - } 81 + }
  82 + uni.$u.toast("网络波动请再试~")
85 return Promise.reject(error) 83 return Promise.reject(error)
86 }); 84 });
87 export default instance; 85 export default instance;
@@ -89,3 +87,10 @@ export default instance; @@ -89,3 +87,10 @@ export default instance;
89 export function setRequestToken(token) { 87 export function setRequestToken(token) {
90 instance.defaults.headers.common["Authorization"] = `${token}`; 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,34 +3,16 @@
3 <view class="u-tabs__wrapper"> 3 <view class="u-tabs__wrapper">
4 <slot name="left" /> 4 <slot name="left" />
5 <view class="u-tabs__wrapper__scroll-view-wrapper"> 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 :isDot="item.badge && item.badge.isDot || propsBadge.isDot" 16 :isDot="item.badge && item.badge.isDot || propsBadge.isDot"
35 :value="item.badge && item.badge.value || propsBadge.value" 17 :value="item.badge && item.badge.value || propsBadge.value"
36 :max="item.badge && item.badge.max || propsBadge.max" 18 :max="item.badge && item.badge.max || propsBadge.max"
@@ -41,35 +23,26 @@ @@ -41,35 +23,26 @@
41 :shape="item.badge && item.badge.shape || propsBadge.shape" 23 :shape="item.badge && item.badge.shape || propsBadge.shape"
42 :numberType="item.badge && item.badge.numberType || propsBadge.numberType" 24 :numberType="item.badge && item.badge.numberType || propsBadge.numberType"
43 :inverted="item.badge && item.badge.inverted || propsBadge.inverted" 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 </view> 27 </view>
47 <!-- #ifdef APP-NVUE --> 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 </view> 35 </view>
59 <!-- #endif --> 36 <!-- #endif -->
60 <!-- #ifndef APP-NVUE --> 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 </view> 46 </view>
74 <!-- #endif --> 47 <!-- #endif -->
75 </view> 48 </view>
@@ -81,278 +54,268 @@ @@ -81,278 +54,268 @@
81 </template> 54 </template>
82 55
83 <script> 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 this.resize() 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 </script> 259 </script>
297 260
298 <style lang="scss" scoped> 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 @include flex; 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 @include flex; 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 &--disabled { 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 </style> 321 </style>