Commit caab2d9a71bc59d83bb8db4e275222e55af4211a

Authored by shaofan
1 parent 6a1f8b67

优化接口响应时间,提升系统性能

src/components/AppMenuTree.vue
@@ -25,6 +25,7 @@ import { @@ -25,6 +25,7 @@ import {
25 ControlOutlined, 25 ControlOutlined,
26 GlobalOutlined, 26 GlobalOutlined,
27 HomeOutlined, 27 HomeOutlined,
  28 + MessageOutlined,
28 SettingOutlined, 29 SettingOutlined,
29 ShopOutlined, 30 ShopOutlined,
30 StarOutlined, 31 StarOutlined,
@@ -51,6 +52,7 @@ const iconMap: Record<string, Component> = { @@ -51,6 +52,7 @@ const iconMap: Record<string, Component> = {
51 TeamOutlined, 52 TeamOutlined,
52 TrophyOutlined, 53 TrophyOutlined,
53 SettingOutlined, 54 SettingOutlined,
  55 + MessageOutlined,
54 } 56 }
55 57
56 const codeIconMap: Record<string, Component> = { 58 const codeIconMap: Record<string, Component> = {
src/config/menu.ts
@@ -19,6 +19,7 @@ export const iconRegistry: Record&lt;string, string&gt; = { @@ -19,6 +19,7 @@ export const iconRegistry: Record&lt;string, string&gt; = {
19 TeamOutlined: 'team', 19 TeamOutlined: 'team',
20 TrophyOutlined: 'trophy', 20 TrophyOutlined: 'trophy',
21 SettingOutlined: 'setting', 21 SettingOutlined: 'setting',
  22 + MessageOutlined: 'message',
22 } 23 }
23 24
24 export const pinnedQuickLinks: QuickLinkItem[] = [ 25 export const pinnedQuickLinks: QuickLinkItem[] = [
src/views/message/MessageList.vue
@@ -3,6 +3,18 @@ @@ -3,6 +3,18 @@
3 <a-card title="消息管理" :bordered="false"> 3 <a-card title="消息管理" :bordered="false">
4 <div class="list-toolbar"> 4 <div class="list-toolbar">
5 <div class="list-toolbar-left"> 5 <div class="list-toolbar-left">
  6 + <a-select
  7 + v-if="isAdmin"
  8 + v-model:value="selectedCityId"
  9 + placeholder="请选择租户"
  10 + style="width: 180px"
  11 + @change="handleCityChange"
  12 + >
  13 + <a-select-option v-for="item in cityList" :key="item.id" :value="item.id">
  14 + {{ item.name }}
  15 + </a-select-option>
  16 + </a-select>
  17 + <div v-else class="managed-city-pill">当前租户:{{ currentCityName }}</div>
6 <a-input 18 <a-input
7 v-model:value="searchForm.riderId" 19 v-model:value="searchForm.riderId"
8 placeholder="骑手ID" 20 placeholder="骑手ID"
@@ -18,14 +30,22 @@ @@ -18,14 +30,22 @@
18 <a-select-option :value="1">订单消息</a-select-option> 30 <a-select-option :value="1">订单消息</a-select-option>
19 <a-select-option :value="2">系统通知</a-select-option> 31 <a-select-option :value="2">系统通知</a-select-option>
20 </a-select> 32 </a-select>
21 - <a-button type="primary" @click="loadList">查询</a-button> 33 + <a-button type="primary" :disabled="!canQuery" @click="handleSearch">查询</a-button>
22 </div> 34 </div>
23 <div class="list-toolbar-right"> 35 <div class="list-toolbar-right">
24 - <a-button type="primary" @click="openSend">发送消息</a-button>  
25 - <a-button @click="openBroadcast">群发消息</a-button> 36 + <a-button type="primary" :disabled="!canQuery" @click="openSend">发送消息</a-button>
  37 + <a-button :disabled="!canQuery" @click="openBroadcast">群发消息</a-button>
26 </div> 38 </div>
27 </div> 39 </div>
28 40
  41 + <a-alert
  42 + v-if="isAdmin"
  43 + type="info"
  44 + show-icon
  45 + message="平台管理员需要先选择租户,消息列表、单发和群发都会限定在所选租户内。"
  46 + style="margin-bottom: 16px"
  47 + />
  48 +
29 <a-table 49 <a-table
30 :dataSource="list" 50 :dataSource="list"
31 :columns="columns" 51 :columns="columns"
@@ -59,6 +79,12 @@ @@ -59,6 +79,12 @@
59 @ok="handleSend" 79 @ok="handleSend"
60 :confirmLoading="sending" 80 :confirmLoading="sending"
61 > 81 >
  82 + <a-alert
  83 + :message="`将发送给当前租户(${currentCityName})下的指定骑手`"
  84 + type="info"
  85 + show-icon
  86 + style="margin-bottom: 16px"
  87 + />
62 <a-form :model="sendForm" layout="vertical"> 88 <a-form :model="sendForm" layout="vertical">
63 <a-form-item label="骑手ID" required> 89 <a-form-item label="骑手ID" required>
64 <a-input-number v-model:value="sendForm.riderId" style="width: 100%" placeholder="请输入骑手ID" /> 90 <a-input-number v-model:value="sendForm.riderId" style="width: 100%" placeholder="请输入骑手ID" />
@@ -86,7 +112,7 @@ @@ -86,7 +112,7 @@
86 :confirmLoading="broadcasting" 112 :confirmLoading="broadcasting"
87 > 113 >
88 <a-alert 114 <a-alert
89 - message="将发送给当前城市所有正常状态的骑手" 115 + :message="`将发送给当前租户(${currentCityName})所有正常状态的骑手`"
90 type="warning" 116 type="warning"
91 show-icon 117 show-icon
92 style="margin-bottom: 16px" 118 style="margin-bottom: 16px"
@@ -113,14 +139,18 @@ @@ -113,14 +139,18 @@
113 import { onMounted, reactive, ref, computed } from 'vue' 139 import { onMounted, reactive, ref, computed } from 'vue'
114 import { message } from 'ant-design-vue' 140 import { message } from 'ant-design-vue'
115 import { messageApi } from '@/api' 141 import { messageApi } from '@/api'
  142 +import { useRoleCityList } from '@/composables/useRoleCityList'
116 import type { TablePaginationConfig } from 'ant-design-vue' 143 import type { TablePaginationConfig } from 'ant-design-vue'
117 144
  145 +const { isAdmin, managedCityId, managedCityName, cityList, loadCities, getCityName } = useRoleCityList()
  146 +
118 const loading = ref(false) 147 const loading = ref(false)
119 const sending = ref(false) 148 const sending = ref(false)
120 const broadcasting = ref(false) 149 const broadcasting = ref(false)
121 const list = ref<any[]>([]) 150 const list = ref<any[]>([])
122 const sendVisible = ref(false) 151 const sendVisible = ref(false)
123 const broadcastVisible = ref(false) 152 const broadcastVisible = ref(false)
  153 +const selectedCityId = ref<number | undefined>()
124 154
125 const searchForm = reactive({ 155 const searchForm = reactive({
126 riderId: undefined as number | undefined, 156 riderId: undefined as number | undefined,
@@ -143,6 +173,8 @@ const broadcastForm = reactive({ @@ -143,6 +173,8 @@ const broadcastForm = reactive({
143 const currentPage = ref(1) 173 const currentPage = ref(1)
144 const pageSize = ref(20) 174 const pageSize = ref(20)
145 const total = ref(0) 175 const total = ref(0)
  176 +const canQuery = computed(() => !!selectedCityId.value)
  177 +const currentCityName = computed(() => selectedCityId.value ? getCityName(selectedCityId.value) : managedCityName.value || '-')
146 178
147 const pagination = computed<TablePaginationConfig>(() => ({ 179 const pagination = computed<TablePaginationConfig>(() => ({
148 current: currentPage.value, 180 current: currentPage.value,
@@ -163,9 +195,15 @@ const columns = [ @@ -163,9 +195,15 @@ const columns = [
163 ] 195 ]
164 196
165 async function loadList() { 197 async function loadList() {
  198 + if (!selectedCityId.value) {
  199 + list.value = []
  200 + total.value = 0
  201 + return
  202 + }
166 loading.value = true 203 loading.value = true
167 try { 204 try {
168 const res: any = await messageApi.list({ 205 const res: any = await messageApi.list({
  206 + cityId: selectedCityId.value,
169 riderId: searchForm.riderId, 207 riderId: searchForm.riderId,
170 type: searchForm.type, 208 type: searchForm.type,
171 page: currentPage.value, 209 page: currentPage.value,
@@ -180,6 +218,16 @@ async function loadList() { @@ -180,6 +218,16 @@ async function loadList() {
180 } 218 }
181 } 219 }
182 220
  221 +function handleSearch() {
  222 + currentPage.value = 1
  223 + loadList()
  224 +}
  225 +
  226 +function handleCityChange() {
  227 + currentPage.value = 1
  228 + loadList()
  229 +}
  230 +
183 function handleTableChange(pag: TablePaginationConfig) { 231 function handleTableChange(pag: TablePaginationConfig) {
184 const nextPage = pag.current ?? 1 232 const nextPage = pag.current ?? 1
185 if (nextPage === currentPage.value) return 233 if (nextPage === currentPage.value) return
@@ -187,24 +235,35 @@ function handleTableChange(pag: TablePaginationConfig) { @@ -187,24 +235,35 @@ function handleTableChange(pag: TablePaginationConfig) {
187 loadList() 235 loadList()
188 } 236 }
189 237
  238 +function ensureCitySelected() {
  239 + if (!selectedCityId.value) {
  240 + message.error('请先选择租户')
  241 + return false
  242 + }
  243 + return true
  244 +}
  245 +
190 function openSend() { 246 function openSend() {
  247 + if (!ensureCitySelected()) return
191 Object.assign(sendForm, { riderId: undefined, type: 2, title: '', content: '' }) 248 Object.assign(sendForm, { riderId: undefined, type: 2, title: '', content: '' })
192 sendVisible.value = true 249 sendVisible.value = true
193 } 250 }
194 251
195 function openBroadcast() { 252 function openBroadcast() {
  253 + if (!ensureCitySelected()) return
196 Object.assign(broadcastForm, { type: 2, title: '', content: '' }) 254 Object.assign(broadcastForm, { type: 2, title: '', content: '' })
197 broadcastVisible.value = true 255 broadcastVisible.value = true
198 } 256 }
199 257
200 async function handleSend() { 258 async function handleSend() {
  259 + if (!ensureCitySelected()) return
201 if (!sendForm.riderId || !sendForm.title || !sendForm.content) { 260 if (!sendForm.riderId || !sendForm.title || !sendForm.content) {
202 message.error('请填写完整信息') 261 message.error('请填写完整信息')
203 return 262 return
204 } 263 }
205 sending.value = true 264 sending.value = true
206 try { 265 try {
207 - await messageApi.send(sendForm) 266 + await messageApi.send({ ...sendForm, cityId: selectedCityId.value })
208 message.success('发送成功') 267 message.success('发送成功')
209 sendVisible.value = false 268 sendVisible.value = false
210 loadList() 269 loadList()
@@ -214,13 +273,14 @@ async function handleSend() { @@ -214,13 +273,14 @@ async function handleSend() {
214 } 273 }
215 274
216 async function handleBroadcast() { 275 async function handleBroadcast() {
  276 + if (!ensureCitySelected()) return
217 if (!broadcastForm.title || !broadcastForm.content) { 277 if (!broadcastForm.title || !broadcastForm.content) {
218 message.error('请填写完整信息') 278 message.error('请填写完整信息')
219 return 279 return
220 } 280 }
221 broadcasting.value = true 281 broadcasting.value = true
222 try { 282 try {
223 - await messageApi.broadcast(broadcastForm) 283 + await messageApi.broadcast({ ...broadcastForm, cityId: selectedCityId.value })
224 message.success('群发成功') 284 message.success('群发成功')
225 broadcastVisible.value = false 285 broadcastVisible.value = false
226 loadList() 286 loadList()
@@ -242,18 +302,26 @@ function formatTime(timestamp: number) { @@ -242,18 +302,26 @@ function formatTime(timestamp: number) {
242 }) 302 })
243 } 303 }
244 304
245 -onMounted(loadList) 305 +onMounted(async () => {
  306 + await loadCities()
  307 + if (!isAdmin.value) {
  308 + selectedCityId.value = managedCityId.value
  309 + await loadList()
  310 + }
  311 +})
246 </script> 312 </script>
247 313
248 <style scoped> 314 <style scoped>
249 .list-toolbar { 315 .list-toolbar {
250 display: flex; 316 display: flex;
251 justify-content: space-between; 317 justify-content: space-between;
  318 + gap: 12px;
252 margin-bottom: 16px; 319 margin-bottom: 16px;
253 } 320 }
254 321
255 .list-toolbar-left { 322 .list-toolbar-left {
256 display: flex; 323 display: flex;
  324 + flex-wrap: wrap;
257 gap: 8px; 325 gap: 8px;
258 } 326 }
259 327
@@ -261,4 +329,16 @@ onMounted(loadList) @@ -261,4 +329,16 @@ onMounted(loadList)
261 display: flex; 329 display: flex;
262 gap: 8px; 330 gap: 8px;
263 } 331 }
  332 +
  333 +.managed-city-pill {
  334 + display: inline-flex;
  335 + align-items: center;
  336 + min-height: 32px;
  337 + padding: 0 12px;
  338 + border: 1px solid var(--line);
  339 + border-radius: 10px;
  340 + background: var(--panel-strong);
  341 + color: var(--text-main);
  342 + font-size: 13px;
  343 +}
264 </style> 344 </style>
src/views/system/MenuManage.vue
@@ -213,6 +213,7 @@ import { @@ -213,6 +213,7 @@ import {
213 ControlOutlined, 213 ControlOutlined,
214 GlobalOutlined, 214 GlobalOutlined,
215 HomeOutlined, 215 HomeOutlined,
  216 + MessageOutlined,
216 SettingOutlined, 217 SettingOutlined,
217 ShopOutlined, 218 ShopOutlined,
218 StarOutlined, 219 StarOutlined,
@@ -254,6 +255,7 @@ const iconOptions = [ @@ -254,6 +255,7 @@ const iconOptions = [
254 'TeamOutlined', 255 'TeamOutlined',
255 'TrophyOutlined', 256 'TrophyOutlined',
256 'SettingOutlined', 257 'SettingOutlined',
  258 + 'MessageOutlined',
257 ] 259 ]
258 260
259 const iconMap: Record<string, any> = { 261 const iconMap: Record<string, any> = {
@@ -269,6 +271,7 @@ const iconMap: Record&lt;string, any&gt; = { @@ -269,6 +271,7 @@ const iconMap: Record&lt;string, any&gt; = {
269 TeamOutlined, 271 TeamOutlined,
270 TrophyOutlined, 272 TrophyOutlined,
271 SettingOutlined, 273 SettingOutlined,
  274 + MessageOutlined,
272 } 275 }
273 276
274 function resolveIcon(icon?: string) { 277 function resolveIcon(icon?: string) {
src/views/system/RoleMenuAssign.vue
@@ -101,6 +101,7 @@ import { @@ -101,6 +101,7 @@ import {
101 ControlOutlined, 101 ControlOutlined,
102 GlobalOutlined, 102 GlobalOutlined,
103 HomeOutlined, 103 HomeOutlined,
  104 + MessageOutlined,
104 SettingOutlined, 105 SettingOutlined,
105 ShopOutlined, 106 ShopOutlined,
106 StarOutlined, 107 StarOutlined,
@@ -141,6 +142,7 @@ const iconMap: Record&lt;string, any&gt; = { @@ -141,6 +142,7 @@ const iconMap: Record&lt;string, any&gt; = {
141 TeamOutlined, 142 TeamOutlined,
142 TrophyOutlined, 143 TrophyOutlined,
143 SettingOutlined, 144 SettingOutlined,
  145 + MessageOutlined,
144 } 146 }
145 147
146 function resolveIcon(icon?: string) { 148 function resolveIcon(icon?: string) {