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 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
  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 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(() =&gt; {
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(() =&gt; {
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 = () =&gt; {
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(() =&gt; {
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(() =&gt; {
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 = () =&gt; {
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 = () =&gt; {
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 = () =&gt; {
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) =&gt; {
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
... ... @@ -12,7 +12,7 @@ export const useMainStore = defineStore(
12 12 persist: {
13 13 enabled: true,
14 14 H5Storage: localStorage,
15   - // 调整为兼容多端的API
  15 + // 调整为兼容多端的API
16 16 storage: {
17 17 setItem(key, value) {
18 18 uni.setStorageSync(key, value)
... ...
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>
... ...