浏览代码

feat:权限、销售线索加趋势图,趋势图加列表

zhangxin 1 月之前
父节点
当前提交
daf0ecf09f

+ 1 - 3
components/custom-table/index.scss

@@ -27,9 +27,7 @@
27 27
   }
28 28
 }
29 29
 
30
-::v-deep .uni-scroll-view{
31
-  height: calc(100vh - 260rpx);
32
-}
30
+
33 31
 
34 32
 ::v-deep .uni-table {
35 33
   width: 100%;

+ 6 - 1
components/custom-table/index.vue

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <scroll-view class="custom-table" scroll-y="true" @scrolltolower="handleScrollLower">
2
+  <scroll-view class="custom-table" scroll-y="true" :style="{ height: height }" @scrolltolower="handleScrollLower">
3 3
     <uni-table
4 4
       ref="tableRef"
5 5
       :border="border"
@@ -137,6 +137,11 @@ export default {
137 137
     index: {
138 138
       type: Number,
139 139
       default: 1
140
+    },
141
+    // 表格高度
142
+    height: {
143
+      type: [String, Number],
144
+      default: 'calc(100vh - 260rpx)'
140 145
     }
141 146
   },
142 147
   data() {

+ 28 - 0
pages/clue/mixins/clue.js

@@ -183,6 +183,12 @@ export default {
183 183
 			maxPrice: [],
184 184
 			minPrice: [],
185 185
 			chartShow: false,
186
+			tableData: [],
187
+			date:'',
188
+			columns: [
189
+				{ label: '型号', prop: 'model'},
190
+				{ label: '价格(元)', prop: 'price' },
191
+			],
186 192
 		}
187 193
 	},
188 194
 	onPullDownRefresh() {
@@ -213,6 +219,8 @@ export default {
213 219
 			},
214 220
 			handleTrendConfirm() {
215 221
 				this.model = ""
222
+				this.date = ""
223
+				this.tableData = []
216 224
 				this.chartShow = false
217 225
 				this.trendModal = false;
218 226
 			},
@@ -274,6 +282,26 @@ export default {
274 282
 					})
275 283
 				}
276 284
 			},
285
+			handleChartClick(event) {
286
+				console.log(event);
287
+				const  index  = event.currentIndex.index;
288
+				// 获取点击的日期
289
+				const date = this.chartData.categories[index];
290
+				this.date = date;
291
+				
292
+				// 构建该日期的所有型号价格数据
293
+				const tableData = [];
294
+				this.chartData.series.forEach(series => {
295
+					const price = series.data[index];
296
+					if (price !== null) {
297
+						tableData.push({
298
+							model: series.name,
299
+							price: price
300
+						});
301
+					}
302
+				});
303
+				this.tableData = tableData;
304
+			},
277 305
 			getRandomColor(){
278 306
 				var letters = '0123456789ABCDEF';
279 307
 				var color = '#';

+ 18 - 1
pages/privateClue/index.vue

@@ -48,8 +48,23 @@
48 48
 			groupChild="clueTagDataList" label-key="name" value-key="id" placeholder="请选择线索标签"
49 49
 			v-model="queryParams.allTagList" multiple clearable ref="clueTag"
50 50
 			@confirm="handleClueTagConfirm"></group-select>
51
+		<u-modal :show="trendModal" title="价格趋势" @confirm="handleTrendConfirm" confirmText="关闭弹窗">
52
+			<view class="trend_modal">
53
+				<u-search placeholder="请输入型号" v-model="model" @blur="searchTrend" @custom="searchTrend"></u-search>
54
+				<view class="charts_box" v-if="chartShow">
55
+					<u--text type="primary" :text="`最大价格:${Math.max(...maxPrice)}元`"></u--text>
56
+					<u--text type="warning" :text="`最小价格:${Math.min(...minPrice)}元`"></u--text>
57
+					<qiun-data-charts type="line" :chartData="chartData" canvasId="trendChart" :opts="opts" :ontouch="true" tooltipFormat="tooltipFormatPrice"
58
+						width="700rpx" height="500rpx" backgroundColor="#ffffff" @getIndex="handleChartClick" />
59
+				</view>
60
+				<u--text v-if="tableData.length > 0" :text="'日期:' + date"></u--text>
61
+				<Table ref="customTable" v-if="tableData.length > 0" :tableData="tableData" height="100px" :columns="columns" stripe></Table>
62
+			</view>
63
+		</u-modal>
51 64
 			
52
-			
65
+		<view class="suspension_button trend" @click="handleTrend">
66
+			趋势
67
+		</view>
53 68
 		<view class="suspension_button" @click="handleAddClue">
54 69
 			新增
55 70
 		</view>
@@ -62,6 +77,7 @@
62 77
 	import post from "@/pages/clue/post/index.vue";
63 78
 	import sort from "@/pages/clue/components/sort.vue";
64 79
 	import filterQuery from "@/pages/clue/components/filterQuery.vue";
80
+	import Table from '@/components/custom-table/index.vue'
65 81
 	export default {
66 82
 		onPullDownRefresh() {
67 83
 			uni.stopPullDownRefresh();
@@ -71,6 +87,7 @@
71 87
 			post,
72 88
 			sort,
73 89
 			filterQuery,
90
+			Table,
74 91
 		},
75 92
 		mixins: [clue],
76 93
 		onLoad(option) {

+ 1 - 1
pages/publicClue/index.vue

@@ -55,7 +55,7 @@
55 55
 					<u--text type="primary" :text="`最大价格:${Math.max(...maxPrice)}元`"></u--text>
56 56
 					<u--text type="warning" :text="`最小价格:${Math.min(...minPrice)}元`"></u--text>
57 57
 					<qiun-data-charts type="line" :chartData="chartData" canvasId="trendChart" :opts="opts" :ontouch="true" tooltipFormat="tooltipFormatPrice"
58
-						width="700rpx" height="500rpx" backgroundColor="#ffffff" />
58
+						width="700rpx" height="500rpx" backgroundColor="#ffffff" @getIndex="handleChartClick" />
59 59
 				</view>
60 60
 			</view>
61 61
 		</u-modal>

+ 38 - 18
pages/setting/index.vue

@@ -72,29 +72,47 @@
72 72
 		methods: {
73 73
 			handleSwitchRole(){
74 74
 					this.columns = [];
75
-					let availableRoles = this.$store.state.user.availableRoles;
75
+					let roles = this.$store.state.user.availableRoles;
76 76
 					let roleOptions = [];
77
-					
78
-					if (availableRoles.includes('admin')) {
77
+					const hasAdminRole = roles.some(role => role == 'admin');
78
+					const hasCrmRole = roles.some(role => role.includes('CRM'));
79
+					const hasWarehouser = roles.some(role => role == 'WAREHOUSER');
80
+					const hasSalesman = roles.some(role => role == 'SALESMAN');
81
+
82
+					if(hasAdminRole){
79 83
 						roleOptions.push(
80 84
 							{ label: 'CRM权限', value: 'CRM' },
81 85
 							{ label: '仓库权限', value: 'WAREHOUSER' },
82 86
 							{ label: '销售权限', value: 'SALESMAN' },
83 87
 						);
84
-					} else {
85
-						availableRoles.forEach(role => {
86
-							switch (role) {
87
-								case 'SALESMAN':
88
-									roleOptions.push({ label: '销售权限', value: 'SALESMAN' });
89
-									break;
90
-								case 'WAREHOUSER':
91
-									roleOptions.push({ label: '仓库权限', value: 'WAREHOUSER' });
92
-									break;
93
-								case 'CRM':
94
-									roleOptions.push({ label: 'CRM权限', value: 'CRM' });
95
-									break;
96
-							}
97
-						});
88
+					}else if(hasWarehouser && hasSalesman && hasCrmRole){
89
+						roleOptions.push(
90
+							{ label: 'CRM权限', value: 'CRM' },
91
+							{ label: '仓库权限', value: 'WAREHOUSER' },
92
+							{ label: '销售权限', value: 'SALESMAN' }
93
+						);
94
+					}else if(hasCrmRole && hasWarehouser){
95
+						roleOptions.push(
96
+							{ label: 'CRM权限', value: 'CRM' },
97
+							{ label: '仓库权限', value: 'WAREHOUSER' }
98
+						);
99
+					}else if(hasCrmRole && hasSalesman){
100
+						roleOptions.push(
101
+							{ label: 'CRM权限', value: 'CRM' },
102
+							{ label: '仓库权限', value: 'WAREHOUSER' },
103
+							{ label: '销售权限', value: 'SALESMAN' }
104
+						);
105
+					}else if(hasWarehouser && hasSalesman){
106
+						roleOptions.push(
107
+							{ label: '仓库权限', value: 'WAREHOUSER' },
108
+							{ label: '销售权限', value: 'SALESMAN' }
109
+						);
110
+					}else if(hasCrmRole){
111
+						roleOptions.push({ label: 'CRM权限', value: 'CRM' });
112
+					}else if(hasWarehouser){
113
+						roleOptions.push({ label: '仓库权限', value: 'WAREHOUSER' });
114
+					}else if(hasSalesman){
115
+						roleOptions.push({ label: '销售权限', value: 'SALESMAN' },{ label: '仓库权限', value: 'WAREHOUSER' });
98 116
 					}
99 117
 					
100 118
 					this.columns = [roleOptions];
@@ -115,9 +133,11 @@
115 133
 			},
116 134
 			confirm() {
117 135
 				// 停止电话监听
118
-				this.$store.dispatch("call/stopPhoneListener").catch(error => {
136
+				//#ifdef APP-PLUS
137
+				this.$store.dispatch("call/stopPhoneListener", null, { root: true }).catch(error => {
119 138
 					console.error('退出登录时停止电话监听失败:', error);
120 139
 				});
140
+				//#endif
121 141
 				
122 142
 				this.$store.dispatch("user/logout").then(()=>{
123 143
 					uni.$u.toast("退出成功");

+ 6 - 4
pages/wareHouse/components/orderList/index.vue

@@ -17,7 +17,7 @@
17 17
                         <jtimePickerPopup :isShowShortTimeList="true" shortTimeTitle="快捷时间" :shortTimeList="shortTimeList"
18 18
                             :isShowSeletTimeTitle="true" seletTimeTitle="时间选择" cancelText="取消" confirmText="确认"
19 19
                             :endSelectMonth="-1" :endSelectDay="-1" beginTimePlaceHolder='开始时间' endTimePlaceHolder="结束时间"
20
-                            :isDateTypeRange="true" :isShowSelectedTimeEcho="true" @confirm="getSelectTime"
20
+                            :isDateTypeRange="true" :isShowSelectedTimeEcho="true" @confirm="getSelectTime" :defaultSelect="0"
21 21
                             ref="jtimePickerPopupRef">
22 22
 					    </jtimePickerPopup>
23 23
                     </u-form-item>
@@ -42,16 +42,18 @@
42 42
                 <view class="order_item" v-for="(item, index) in orderList" :key="index">
43 43
                     <u-swipe-action>
44 44
                         <u-swipe-action-item :options="swipeOptions" @click="(e) => handleSwipeClick(e, item)">
45
+                             <view class="order_col_1">
46
+                                <view class="order_info title">品牌:{{ item.dictLabel || '-' }}</view>
47
+                             </view>
45 48
                             <view class="order_col_2">
46
-                                <view class="order_info">品牌:{{ item.dictLabel || '-' }}</view>
47 49
                                 <view class="order_info">付款方式:{{ payTypeFormatter(item.payType) || '-' }}</view>
48 50
                                 <view class="order_info">开单人:{{ item.recyclePerson || '-' }}</view>
49 51
                                 <view class="order_info">开单数量:{{ item.quantity || '-' }}</view>
50 52
                                 <view class="order_info">开单日期:{{ orderDateFormatter(item.orderDate) || '-' }}</view>
51 53
                                 <view class="order_info">订单类型:{{ orderTypeFormatter(item.orderType) || '-' }}</view>
52 54
                                 <view class="order_info">商品分类:{{ typeFormatter(item.type) || '-' }}</view>
53
-                                <view class="order_info">成交金额:{{ item.dealPrice || '-' }}元</view>
54
-                                <view class="order_info">实收总计:{{ item.amountReceived || '-' }}元</view>
55
+                                <view class="order_info money">成交金额:{{ item.dealPrice || '-' }}元</view>
56
+                                <view class="order_info money">实收总计:{{ item.amountReceived || '-' }}元</view>
55 57
                             </view>
56 58
                             <view class="order_col_1">
57 59
                                 <view class="order_info">开单备注:{{ item.orderRemark || '-' }}</view>

+ 35 - 16
pages/wareHouse/components/searchFilter.vue

@@ -13,10 +13,14 @@
13 13
             <u-form-item label="位置" labelWidth="70">
14 14
                 <u-input v-model="formData.location" fontSize="14" clearable border="bottom"></u-input>
15 15
             </u-form-item>
16
-            <u-form-item label="回收时间" labelWidth="70" @click="recycleTimeShow = true">
17
-                <Cell :val="formData.recycleTime" :isDelete="true" :border="true" @handleClear="clear('recycleTime')">  </Cell>
18
-                <u-datetime-picker  :show="recycleTimeShow" v-model="recycleTimeDefault" mode="date"  @confirm="confirmRecycleTime" @close="recycleTimeShow = false"
19
-                            @cancel="recycleTimeShow = false"></u-datetime-picker>
16
+            <u-form-item label="回收时间" labelWidth="70" @click="openTimePicker">
17
+                <Cell :val="time" :isDelete="true" :border="true" @handleClear="clear('time')">  </Cell>
18
+                <jtimePickerPopup :isShowShortTimeList="true" shortTimeTitle="快捷时间" :shortTimeList="shortTimeList"
19
+                    :isShowSeletTimeTitle="true" seletTimeTitle="时间选择" cancelText="取消" confirmText="确认"
20
+                    :endSelectMonth="-1" :endSelectDay="-1" beginTimePlaceHolder='开始时间' endTimePlaceHolder="结束时间"
21
+                    :isDateTypeRange="true" :isShowSelectedTimeEcho="true" @confirm="getSelectTime" :defaultSelect="0"
22
+                    ref="jtimePickerPopupRef">
23
+                </jtimePickerPopup>
20 24
             </u-form-item>
21 25
             <u-form-item label="回收人员" labelWidth="70" @click="recyclePersonClick">
22 26
                 <Cell :val="formData.recyclePerson" :isDelete="true" :border="true" @handleClear="clear('recyclePerson')"></Cell>
@@ -45,13 +49,15 @@ import Cell from '@/components/custom-cell/index.vue'
45 49
 import BrandList from '@/components/brand-list/index.vue'
46 50
 import PersonPicker from '@/components/person-picker/index.vue'
47 51
 import TabSelect from '@/components/custom-tab-select/index.vue'
48
-import { productAttributeList, stockStatusListAll } from '../js/public.js'
52
+import { productAttributeList, stockStatusListAll,shortTimeList } from '../js/public.js'
53
+import jtimePickerPopup from '@/uni_modules/jtime-picker-popup/components/JTimePicker/JTimePicker.vue';
49 54
 export default {
50 55
     components: {
51 56
         Cell,
52 57
         BrandList,
53 58
         PersonPicker,
54 59
         TabSelect,
60
+        jtimePickerPopup,
55 61
     },
56 62
     name: 'searchFilter',
57 63
     emits: ['confirm'],
@@ -64,7 +70,8 @@ export default {
64 70
                 minPrice: '',
65 71
                 maxPrice: '',
66 72
                 location: '',
67
-                recycleTime: '',
73
+                startTime: '',
74
+                endTime: '',
68 75
                 recyclePerson:'',
69 76
                 recyclePersonId: '',
70 77
                 identifyingPerson:'',
@@ -72,8 +79,8 @@ export default {
72 79
                 productAttribute: [],
73 80
                 stockStatus: '',
74 81
             },
75
-            recycleTimeDefault: new Date().getTime(),
76
-            recycleTimeShow: false,
82
+            time:'',
83
+            shortTimeList: shortTimeList,
77 84
             recyclePersonList: [],
78 85
             // 将导入的变量在data中重新定义,确保模板能够访问
79 86
             productAttributeList: productAttributeList,
@@ -85,6 +92,7 @@ export default {
85 92
     },
86 93
     emits: [],
87 94
     methods: {
95
+        
88 96
         handleSearch() {
89 97
             this.$emit('confirm', this.formData);
90 98
             this.close();
@@ -96,7 +104,8 @@ export default {
96 104
                 minPrice: '',
97 105
                 maxPrice: '',
98 106
                 location: '',
99
-                recycleTime: '',
107
+                startTime: '',
108
+                endTime: '',
100 109
                 recyclePerson:'',
101 110
                 recyclePersonId: '',
102 111
                 identifyingPerson:'',
@@ -104,11 +113,15 @@ export default {
104 113
                 productAttribute: [],
105 114
                 stockStatus: '',
106 115
             };
107
-            this.recycleTimeDefault = new Date().getTime();
108 116
         },
109 117
         open() {
110 118
             this.show = true
111
-            
119
+            this.$nextTick(() => {
120
+                this.$refs.jtimePickerPopupRef.handleInit();
121
+            })
122
+        },
123
+        openTimePicker() {
124
+            this.$refs.jtimePickerPopupRef.pickerShow();
112 125
         },
113 126
         close() {
114 127
             this.show = false
@@ -140,13 +153,19 @@ export default {
140 153
                 this.formData.identifyingPersonId = '';
141 154
                 return;
142 155
             }
156
+            // 回收时间
157
+            if(field == 'time'){
158
+                this.time = '';
159
+                this.formData.startTime = '';
160
+                this.formData.endTime = '';
161
+                return;
162
+            }
143 163
             this.formData[field] = '';
144 164
         },
145
-        confirmRecycleTime(val) {
146
-            this.$nextTick(()=>{
147
-                this.formData.recycleTime = this.$dayjs(val.value).format('YYYY-MM-DD');
148
-            })
149
-            this.recycleTimeShow = false;
165
+        getSelectTime(val) {
166
+            this.formData.startTime = this.$dayjs(val.beginTime).format('YYYY-MM-DD');
167
+            this.formData.endTime = this.$dayjs(val.endTime).format('YYYY-MM-DD');
168
+            this.time = this.$dayjs(val.beginTime).format('YYYY-MM-DD') + ' 至 ' + this.$dayjs(val.endTime).format('YYYY-MM-DD');
150 169
         },
151 170
         recyclePersonClick() {
152 171
             this.$refs.recyclePersonPickerRef.open();

+ 206 - 12
pages/wareHouse/styles/orderList/index.scss

@@ -3,46 +3,240 @@
3 3
 }
4 4
 ::v-deep .order_list{
5 5
     overflow: hidden;
6
-    padding:0 20rpx;
6
+    padding: 0 20rpx;
7 7
     font-size: 28rpx;
8
+    color: #333333;
9
+    background-color: #f5f7fa;
10
+    min-height: 100vh;
11
+    font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
12
+    
8 13
     .search_form{
9 14
         display: flex;
10 15
         align-items: center;
11 16
         justify-content: space-between;
12
-        gap: 10rpx;
17
+        gap: 15rpx;
18
+        margin-top: 20rpx;
19
+        background-color: #ffffff;
20
+        border-radius: 16rpx;
21
+        padding: 20rpx;
22
+        box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
23
+        transition: all 0.3s ease;
13 24
     }
25
+    
14 26
     .btns{
15 27
         display: flex;
16
-        gap:20rpx;
17
-        padding: 20rpx;
28
+        gap: 16rpx;
29
+        padding: 24rpx 20rpx;
30
+        background-color: #ffffff;
31
+        border-top: 1rpx solid #f0f2f5;
32
+        border-radius: 16rpx 16rpx 0 0;
33
+        margin-top: 20rpx;
34
+        
35
+        button{
36
+            flex: 1;
37
+            border-radius: 12rpx;
38
+            height: 88rpx;
39
+            font-size: 30rpx;
40
+            font-weight: 500;
41
+            transition: all 0.3s ease;
42
+            
43
+            &:hover{
44
+                transform: translateY(-2rpx);
45
+                box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
46
+            }
47
+        }
18 48
     }
49
+    
19 50
     .list_wrap{
20 51
         margin-top: 20rpx;
21 52
         overflow: auto;
22
-        height: calc(100vh - 200rpx);
53
+        height: calc(100vh - 280rpx);
23 54
         width: 100%;
55
+        
24 56
         .order_item{
25 57
             background-color: #ffffff;
26 58
             border-radius: 20rpx;
27
-            padding: 20rpx;
59
+            padding: 32rpx;
28 60
             margin-bottom: 20rpx;
29
-            border: 1px solid #f7f6f6;
30
-            box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
31
-            line-height: 44rpx;
61
+            box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
62
+            line-height: 52rpx;
63
+            transition: all 0.3s ease;
64
+            position: relative;
65
+            overflow: hidden;
66
+            
67
+            &::before{
68
+                content: '';
69
+                position: absolute;
70
+                top: 0;
71
+                left: 0;
72
+                width: 6rpx;
73
+                height: 100%;
74
+                background: linear-gradient(180deg, #1a7cec 0%, #5FB8FF 100%);
75
+                border-radius: 20rpx 0 0 20rpx;
76
+            }
77
+            
78
+            
32 79
             .order_col_1{
33 80
                 display: grid;
34
-                flex:1;
81
+                flex: 1;
82
+                margin-top: 24rpx;
83
+                padding-top: 24rpx;
84
+                border-top: 1rpx solid #f0f2f5;
85
+                
86
+                &:first-child{
87
+                    margin-top: 0;
88
+                    padding-top: 0;
89
+                    border-top: none;
90
+                }
35 91
             }
92
+            
36 93
             .order_col_2{
37 94
                 display: grid;
38 95
                 grid-template-columns: repeat(2, 1fr);
39 96
             }
97
+            
98
+            .order_info{
99
+                font-size: 26rpx;
100
+                display: flex;
101
+                align-items: center;
102
+                color: #666666;
103
+                
104
+                &::before{
105
+                    content: '';
106
+                    width: 6rpx;
107
+                    height: 6rpx;
108
+                    border-radius: 50%;
109
+                    background-color: #4A90E2;
110
+                    margin-right: 12rpx;
111
+                }
112
+            }
113
+            
114
+            .title{
115
+                font-weight: 600;
116
+                font-size: 30rpx;
117
+                color: #1a1a1a;
118
+            }
119
+            
120
+            .money{
121
+                font-size: 30rpx;
122
+                font-weight: 700;
123
+                color: #f13939;
124
+                background: linear-gradient(135deg, #FF6B6B 0%, #f7a071 100%);
125
+                -webkit-background-clip: text;
126
+                -webkit-text-fill-color: transparent;
127
+                background-clip: text;
128
+            }
129
+            
40 130
             .scroll_img{
41
-                width: calc(100vw - 80rpx);
131
+                width: calc(100vw - 112rpx);
132
+                border-radius: 12rpx;
133
+                overflow: hidden;
134
+                box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
42 135
             }
43 136
         }
44 137
     }
138
+    
45 139
     .search_pop{
46
-        padding: 40rpx 20rpx;
140
+        padding: 48rpx 24rpx;
141
+        background-color: #ffffff;
142
+        border-radius: 20rpx 20rpx 0 0;
143
+        
144
+        .u-form-item{
145
+            margin-bottom: 36rpx;
146
+            
147
+            &:last-child{
148
+                margin-bottom: 0;
149
+            }
150
+        }
151
+        
152
+        .u-form-item__label{
153
+            font-size: 28rpx;
154
+            font-weight: 500;
155
+            color: #333333;
156
+            margin-bottom: 12rpx;
157
+            display: block;
158
+        }
159
+        
160
+        .u-input{
161
+            border-radius: 12rpx;
162
+            border: 2rpx solid #f0f2f5;
163
+            transition: all 0.3s ease;
164
+            
165
+            &:focus{
166
+                border-color: #4A90E2;
167
+                box-shadow: 0 0 0 4rpx rgba(74, 144, 226, 0.1);
168
+            }
169
+        }
170
+    }
171
+    
172
+    // 美化滑动操作按钮
173
+    .u-swipe-action__item{
174
+        border-radius: 0 20rpx 20rpx 0;
175
+        overflow: hidden;
176
+        
177
+        .u-swipe-action__content{
178
+            border-radius: 20rpx;
179
+            display: flex;
180
+            align-items: center;
181
+            justify-content: center;
182
+            font-size: 28rpx;
183
+            font-weight: 500;
184
+            transition: all 0.3s ease;
185
+            
186
+            &:hover{
187
+                opacity: 0.9;
188
+            }
189
+        }
190
+    }
191
+    
192
+    // 美化空状态
193
+    .u-empty{
194
+        margin-top: 120rpx;
195
+        
196
+        .u-empty__text{
197
+            font-size: 28rpx;
198
+            color: #999999;
199
+            margin-top: 20rpx;
200
+        }
201
+        
202
+        .u-empty__icon{
203
+            width: 160rpx;
204
+            height: 160rpx;
205
+        }
206
+    }
207
+    
208
+    // 自定义滚动条
209
+    ::-webkit-scrollbar{
210
+        width: 6rpx;
211
+        height: 6rpx;
212
+    }
213
+    
214
+    ::-webkit-scrollbar-track{
215
+        background: #f1f1f1;
216
+        border-radius: 3rpx;
217
+    }
218
+    
219
+    ::-webkit-scrollbar-thumb{
220
+        background: #c1c1c1;
221
+        border-radius: 3rpx;
222
+    }
223
+    
224
+    ::-webkit-scrollbar-thumb:hover{
225
+        background: #a8a8a8;
226
+    }
227
+}
228
+
229
+// 响应式设计
230
+@media (max-width: 375px) {
231
+    ::v-deep .order_list{
232
+        .list_wrap{
233
+            .order_item{
234
+                padding: 28rpx;
235
+                
236
+                .order_col_2{
237
+                    grid-template-columns: 1fr;
238
+                }
239
+            }
240
+        }
47 241
     }
48 242
 }

+ 11 - 3
store/modules/call.js

@@ -450,13 +450,21 @@ export default {
450 450
 			commit
451 451
 		}) {
452 452
 			try {
453
-				stopPhoneListener(res => {
453
+				// #ifdef APP-PLUS
454
+				if (typeof stopPhoneListener === 'function') {
455
+					stopPhoneListener(res => {
456
+						commit('SET_PHONE_LISTENING_STATUS', false);
457
+					});
458
+				} else {
454 459
 					commit('SET_PHONE_LISTENING_STATUS', false);
455
-				});
460
+				}
461
+				// #endif
462
+				// #ifndef APP-PLUS
463
+				commit('SET_PHONE_LISTENING_STATUS', false);
464
+				// #endif
456 465
 			} catch (error) {
457 466
 				console.error('停止电话监听失败:', error);
458 467
 				commit('SET_PHONE_LISTENING_STATUS', false);
459
-				throw error;
460 468
 			}
461 469
 		},
462 470
 

+ 35 - 15
store/modules/user.js

@@ -60,28 +60,48 @@ export default {
60 60
 			
61 61
 			const validRoles = [];
62 62
 			
63
+			const hasAdminRole = roles.some(role => role.roleKey === 'admin');
64
+			const hasCrmRole = roles.some(role => role.roleKey && role.roleKey.includes('CRM'));
63 65
 			const hasWarehouser = roles.some(role => role.roleKey === 'WAREHOUSER');
64
-			if (hasWarehouser) {
65
-				validRoles.push('WAREHOUSER');
66
-			}
67
-			
68 66
 			const hasSalesman = roles.some(role => role.roleKey === 'SALESMAN');
69
-			if (hasSalesman) {
67
+
68
+			if (hasAdminRole) {//管理员
69
+				if (hasCrmRole) validRoles.push('CRM');
70
+				if (hasWarehouser) validRoles.push('WAREHOUSER');
71
+				if (hasSalesman) validRoles.push('SALESMAN');
72
+				validRoles.push('admin');
73
+				state.showRoleSwitch = true;
74
+			} else if(hasWarehouser && hasSalesman && hasCrmRole) {//仓库和销售和crm
75
+				validRoles.push('CRM');
76
+				validRoles.push('WAREHOUSER');
70 77
 				validRoles.push('SALESMAN');
78
+				state.showRoleSwitch = true;
79
+			} else if (hasCrmRole && hasWarehouser) {//crm和仓库
80
+				validRoles.push('CRM');
81
+				validRoles.push('WAREHOUSER');
82
+				state.showRoleSwitch = true;
83
+			} else if ((hasCrmRole && hasSalesman)) {//crm和销售
84
+				validRoles.push('CRM');
85
+				validRoles.push('WAREHOUSER');
86
+				validRoles.push('SALESMAN');
87
+				state.showRoleSwitch = true;
88
+			}else if(hasWarehouser && hasSalesman) {//只有仓库和销售
89
+				validRoles.push('WAREHOUSER');
90
+				validRoles.push('SALESMAN');
91
+				state.showRoleSwitch = true;
71 92
 			}
72
-			
73
-			const hasCrmRole = roles.some(role => role.roleKey && role.roleKey.includes('CRM'));
74
-			if (hasCrmRole) {
93
+			else if (hasCrmRole) {//只有crm
75 94
 				validRoles.push('CRM');
95
+				state.showRoleSwitch = false;
96
+			} else if(hasWarehouser){//只有仓库
97
+				validRoles.push('WAREHOUSER');
98
+				state.showRoleSwitch = false;
99
+			}else if (hasSalesman) {//只有销售
100
+				if (hasWarehouser) validRoles.push('WAREHOUSER');
101
+				if (hasSalesman) validRoles.push('SALESMAN');
102
+				state.showRoleSwitch = true;
76 103
 			}
77 104
 
78
-			const hasAdminRole = roles.some(role => role.roleKey === 'admin');
79
-			if (hasAdminRole) {
80
-				validRoles.push('admin');
81
-			}
82
-			
83
-			const showSwitch = validRoles.length >= 2 || roles.some(role => role.roleKey == 'admin');
84
-			state.showRoleSwitch = showSwitch;
85 105
 			state.availableRoles = validRoles;
86 106
 			state.currentRoleIndex = 0;
87 107