From 86b51c1d234c604bc4638357c117dd64218b5d68 Mon Sep 17 00:00:00 2001 From: wx-jincw Date: Sat, 4 Apr 2026 17:36:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=AF=8F=E6=97=A5=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E7=82=B9=E8=B5=9E=E7=82=B9=E8=B8=A9=EF=BC=9Bbigint=E8=BD=AC?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/property.js | 10 + app/pages/supply_chain/stock/index.vue | 4 +- app/pages/supply_chain/wish_menu/index.vue | 386 ++++++++++++++++++--- app/static/images/wg/dislike.png | Bin 0 -> 1546 bytes app/static/images/wg/dislike_.png | Bin 0 -> 1177 bytes app/static/images/wg/like.png | Bin 0 -> 1209 bytes app/static/images/wg/like_.png | Bin 0 -> 788 bytes app/utils/request.js | 10 +- 8 files changed, 365 insertions(+), 45 deletions(-) create mode 100644 app/static/images/wg/dislike.png create mode 100644 app/static/images/wg/dislike_.png create mode 100644 app/static/images/wg/like.png create mode 100644 app/static/images/wg/like_.png diff --git a/app/api/property.js b/app/api/property.js index efbec90..0b864fd 100644 --- a/app/api/property.js +++ b/app/api/property.js @@ -46,6 +46,16 @@ export function likeDailyMenuItem(data) { ); } +// 菜单取消点赞/点踩 +export function cancelLikeDailyMenuItem(data) { + return request.post( + 'autogencode/pmdailymenudtllike/cancelLike', + data, + { useAdminUrl: true }, + data + ); +} + // 菜品排行(点赞/点踩) export function getDailyMenuRanking(params) { return request.get( diff --git a/app/pages/supply_chain/stock/index.vue b/app/pages/supply_chain/stock/index.vue index 34e6fd2..8cadd87 100644 --- a/app/pages/supply_chain/stock/index.vue +++ b/app/pages/supply_chain/stock/index.vue @@ -71,8 +71,8 @@ ref="calendar" :insert="false" :range="false" - :start-date="'2020-01-01'" - :end-date="'2030-12-31'" + :start-date="'2026-01-01'" + :end-date="'2099-12-31'" @confirm="confirm" > diff --git a/app/pages/supply_chain/wish_menu/index.vue b/app/pages/supply_chain/wish_menu/index.vue index 12aa2fc..78fb5bd 100644 --- a/app/pages/supply_chain/wish_menu/index.vue +++ b/app/pages/supply_chain/wish_menu/index.vue @@ -3,14 +3,52 @@ 前一天 - - {{ selectedDate }} - + + + {{ selectedDate }} + + + 后一天 默认当天,可切换查看不同日期菜单 + + + + + {{ canteen.label }} + + + + + + + + + + 当日菜单 @@ -19,18 +57,21 @@ - {{ item.itemName || '未命名菜品' }} - {{ item.remark }} - - ¥{{ item.itemPrice }} + + {{ item.itemName || '未命名菜品' }} + + ¥{{ item.itemPrice }} + - 👎 {{ item.dislikeCount || 0 }} + + {{ item.dislikeCount || 0 }} @@ -59,6 +100,21 @@ + + + + + ✕ + + + {{ rankingDateRange.startDate && rankingDateRange.endDate ? `${rankingDateRange.startDate} 至 ${rankingDateRange.endDate}` : '选择日期范围' }} + + + + + + + @@ -66,9 +122,10 @@ {{ index + 1 }} {{ item.itemName || '未命名菜品' }} - - 👍 {{ item.likeCount || 0 }} - 👎 {{ item.dislikeCount || 0 }} + + + + {{ rankingType === 'like' ? (item.likeCount || 0) : (item.dislikeCount || 0) }} @@ -81,10 +138,12 @@ import { listDailyMenuDetails, likeDailyMenuItem, + cancelLikeDailyMenuItem, getDailyMenuRanking } from '@/api/property.js'; export default { + dicts: ['canteen_name'], data() { return { selectedDate: '', @@ -95,21 +154,53 @@ export default { { key: 'breakfast', label: '早餐', list: [] }, { key: 'lunch', label: '中餐', list: [] }, { key: 'dinner', label: '晚餐', list: [] } - ] + ], + canteens: [], + selectedCanteen: '', + rankingDateRange: { + startDate: '', + endDate: '' + }, + showRankingDatePicker: false }; }, onLoad() { this.selectedDate = this.formatDate(new Date()); + this.rankingDateRange.startDate = this.selectedDate; + this.rankingDateRange.endDate = this.selectedDate; + this.loadCanteens(); this.loadPageData(); }, + mounted() { + // 监听字典数据变化 + this.$on('dictChange', () => { + this.loadCanteens(); + }); + }, + beforeUnmount() { + this.$off('dictChange'); + }, methods: { async loadPageData() { await Promise.all([this.loadMenuByDate(), this.loadRanking()]); }, + loadCanteens() { + const canteenDict = this.dict.get('canteen_name') || []; + this.canteens = canteenDict.map(item => ({ + value: item.dictValue, + label: item.dictLabel + })); + if (this.canteens.length > 0 && !this.selectedCanteen) { + this.selectedCanteen = this.canteens[0].value; + } + }, async loadMenuByDate() { try { uni.showLoading({ title: '加载菜单中...', mask: true }); - const res = await listDailyMenuDetails({ menuDate: this.selectedDate }); + const res = await listDailyMenuDetails({ + menuDate: this.selectedDate, + canteenName: this.selectedCanteen + }); const list = res?.data || []; this.menuList = list; this.groupMeals(list); @@ -147,24 +238,58 @@ export default { normalizeMealType(type) { if (!type) return ''; const v = String(type).trim(); - if (v === '早餐' || v === '0' || v.toLowerCase() === 'breakfast') return 'breakfast'; - if (v === '中餐' || v === '午餐' || v === '1' || v.toLowerCase() === 'lunch') return 'lunch'; - if (v === '晚餐' || v === '2' || v.toLowerCase() === 'dinner') return 'dinner'; + if (v === '早餐' || v === '1' || v.toLowerCase() === 'breakfast') return 'breakfast'; + if (v === '中餐' || v === '午餐' || v === '2' || v.toLowerCase() === 'lunch') return 'lunch'; + if (v === '晚餐' || v === '3' || v.toLowerCase() === 'dinner') return 'dinner'; return ''; }, async submitLike(item, likeType) { if (!item || !item.id) return; try { - uni.showLoading({ title: likeType === '1' ? '点赞中...' : '点踩中...', mask: true }); - await likeDailyMenuItem({ - menuDtlId: item.id, - likeType - }); - uni.showToast({ - title: likeType === '1' ? '点赞成功' : '点踩成功', - icon: 'success' - }); - await Promise.all([this.loadMenuByDate(), this.loadRanking()]); + // 判断是否需要取消点赞/点踩 + const isLiked = likeType === '1' && item.isLiked === '1'; + const isDisliked = likeType === '2' && item.isDisliked === '1'; + + if (isLiked || isDisliked) { + uni.showLoading({ title: likeType === '1' ? '取消点赞中...' : '取消点踩中...', mask: true }); + await cancelLikeDailyMenuItem({ + menuDtlId: item.id, + likeType + }); + uni.showToast({ + title: likeType === '1' ? '取消点赞成功' : '取消点踩成功', + icon: 'success' + }); + // 立即更新本地状态,提供即时反馈 + if (likeType === '1') { + item.isLiked = '0'; + item.likeCount = Math.max(0, (item.likeCount || 0) - 1); + } else { + item.isDisliked = '0'; + item.dislikeCount = Math.max(0, (item.dislikeCount || 0) - 1); + } + } else { + uni.showLoading({ title: likeType === '1' ? '点赞中...' : '点踩中...', mask: true }); + await likeDailyMenuItem({ + menuDtlId: item.id, + likeType + }); + uni.showToast({ + title: likeType === '1' ? '点赞成功' : '点踩成功', + icon: 'success' + }); + // 立即更新本地状态,提供即时反馈 + if (likeType === '1') { + item.isLiked = '1'; + item.isDisliked = '0'; + item.likeCount = (item.likeCount || 0) + 1; + } else { + item.isDisliked = '1'; + item.isLiked = '0'; + item.dislikeCount = (item.dislikeCount || 0) + 1; + } + } + // await Promise.all([this.loadMenuByDate(), this.loadRanking()]); } catch (e) { uni.showToast({ title: typeof e === 'string' ? e : '操作失败', @@ -177,10 +302,10 @@ export default { async loadRanking() { try { const res = await getDailyMenuRanking({ - limit: 10, + limit: 20, rankingType: this.rankingType, - startDate: this.selectedDate, - endDate: this.selectedDate + startDate: this.rankingDateRange.startDate, + endDate: this.rankingDateRange.endDate }); this.rankingList = res?.data?.list || []; } catch (e) { @@ -192,21 +317,44 @@ export default { this.rankingType = type; await this.loadRanking(); }, - async onDatePicked(e) { - this.selectedDate = e.detail.value; - await this.loadPageData(); + // 打开日历 + openCalendar() { + this.$refs.calendar.open(); + }, + // 确认日期 + async confirm(e) { + this.selectedDate = e.fulldate; + await this.loadMenuByDate(); }, async changeDateBy(step) { const d = new Date(this.selectedDate.replace(/-/g, '/')); d.setDate(d.getDate() + step); this.selectedDate = this.formatDate(d); - await this.loadPageData(); + await this.loadMenuByDate(); }, formatDate(date) { const y = date.getFullYear(); const m = `${date.getMonth() + 1}`.padStart(2, '0'); const d = `${date.getDate()}`.padStart(2, '0'); return `${y}-${m}-${d}`; + }, + async switchCanteen(canteenValue) { + if (this.selectedCanteen === canteenValue) return; + this.selectedCanteen = canteenValue; + await this.loadPageData(); + }, + openRankingDatePicker() { + this.$refs.rankingCalendar.open(); + }, + async confirmRankingDate(e) { + this.rankingDateRange.startDate = e.range.before; + this.rankingDateRange.endDate = e.range.after; + await this.loadRanking(); + }, + async clearRankingDate() { + this.rankingDateRange.startDate = ''; + this.rankingDateRange.endDate = ''; + await this.loadRanking(); } } }; @@ -219,6 +367,98 @@ export default { padding: 24rpx; } +/* 食堂筛选 */ +.canteen-tabs { + margin-bottom: 20rpx; + overflow-x: auto; + white-space: nowrap; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + + .canteen-tabs-container { + display: inline-flex; + background: #fff; + border-radius: 16rpx; + padding: 8rpx; + } + + .canteen-tab { + padding: 12rpx 24rpx; + margin: 0 4rpx; + border-radius: 999rpx; + font-size: 26rpx; + color: #6b7280; + transition: all 0.3s; + + &.active { + background: #3b82f6; + color: #fff; + font-weight: 600; + } + } +} + +/* 排行榜日期范围选择 */ +.rank-date-range { + margin-bottom: 18rpx; + display: flex; + justify-content: flex-end; +} + +.date-range-container { + display: flex; + align-items: center; + gap: 12rpx; +} + +.date-range-btn { + display: flex; + align-items: center; + padding: 10rpx 16rpx; + background: #f3f4f6; + border-radius: 999rpx; + font-size: 24rpx; + color: #6b7280; + cursor: pointer; + gap: 12rpx; + + .clear-btn { + font-size: 20rpx; + color: #9ca3af; + cursor: pointer; + padding: 0 4rpx; + + &:hover { + color: #ef4444; + } + } + + .date-text { + flex: 1; + font-size: 24rpx; + color: #6b7280; + font-weight: normal; + } + + .icon { + .iconfont { + font-size: 18rpx; + } + } +} + + + +.rank-tabs { + display: flex; + background: #f3f4f6; + border-radius: 999rpx; + padding: 4rpx; +} + .date-card, .section, .meal-card { @@ -248,12 +488,30 @@ export default { font-size: 26rpx; } +.date-picker-container { + display: flex; + align-items: center; +} + .date-text { min-width: 260rpx; text-align: center; font-size: 30rpx; color: #1f2d3d; font-weight: 600; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + text { + margin-right: 10rpx; + } + + .iconfont { + font-size: 20rpx; + color: #666; + } } .date-tip { @@ -290,34 +548,55 @@ export default { .dish-item { padding: 16rpx 0; border-bottom: 1rpx solid #f2f3f7; + display: flex; + align-items: flex-start; + gap: 16rpx; } .dish-item:last-child { border-bottom: none; } +.dish-main { + flex: 1; + min-width: 0; +} + +.dish-info { + display: flex; + align-items: center; + gap: 16rpx; + margin-bottom: 4rpx; +} + .dish-name { font-size: 28rpx; color: #1f2937; font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .dish-desc { - margin-top: 8rpx; color: #6b7280; - font-size: 24rpx; + font-size: 20rpx; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .dish-price { - margin-top: 8rpx; color: #ef4444; font-size: 24rpx; + white-space: nowrap; } .action-row { - margin-top: 12rpx; display: flex; gap: 16rpx; + white-space: nowrap; + align-self: center; } .action { @@ -326,6 +605,15 @@ export default { padding: 0 20rpx; border-radius: 26rpx; font-size: 24rpx; + display: flex; + align-items: center; + gap: 8rpx; +} + +.action-icon { + width: 28rpx; + height: 28rpx; + vertical-align: middle; } .like { @@ -342,6 +630,7 @@ export default { display: flex; align-items: center; justify-content: space-between; + margin-bottom: 18rpx; } .rank-tabs { @@ -401,7 +690,26 @@ export default { .rank-right { font-size: 26rpx; - color: #111827; + color: #6b7280; + display: flex; + align-items: center; + gap: 8rpx; + border-radius: 4rpx; + padding: 2rpx 4rpx; +} + +.rank-right.like { + color: #16a34a; +} + +.rank-right.dislike { + color: #dc2626; +} + +.rank-icon { + width: 28rpx; + height: 28rpx; + vertical-align: middle; } .empty { diff --git a/app/static/images/wg/dislike.png b/app/static/images/wg/dislike.png new file mode 100644 index 0000000000000000000000000000000000000000..0f31abf5c5bf7c3bd09820057f3029f87c4f7c43 GIT binary patch literal 1546 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`1f)iIruq6Z zXaU(A3`~qd49p-UK*-RZ$-n|;Gcc$DX$A)71&j#U1x#>Rl?BWQHb|kx<+G1~hD2tD zM3hAM`dB6B=jtV<VstT4fPE4;bsH1+JHo@{EISEfi{E8w==W>t3(ll z+GC>+vK+}V5TAlYfnK%aveAbJn;n;A+(UK-1{P*d7srqY&bQOOJ*EVT9Cw#hy?jb( zQPdYTuSH_IZ#J&%;D{CxalCNqM62q)PO*aytOtMSBzi3h4ODP(b=B>XbCD1U`J&Jz z#<}%`Nl}_X>6`Mm*3*q2zo@A@wPw$Uvp?q_-~0Uk-RgbS?|;+;=f06VA#wZf{pj#; z^ZJB@1nDTo^S2KkJoxU+nKSF2J$v>(?^nONn(D$+r%oNXaN)wno}Qk}#XNVq|B4&N z9w}+u&C~Y5KV|zx-k%XVViW(}NY>TW^>?{mjy2OPYbRq>??k6rvnz&n~(zljO7a>|@Rk9@TFemY#6s`zPG#@@)Iot-Sh~m$t87 zwJPe^1E*ut=gzHlar04YKKOwD&9lzz)YR0Uz=Xqi{KxF+x0D#4RJiv!eUYrJtb9Gu zzgPeA9~HBE-xl1cxLu~caE6-qzDbQIwg(ghIZe=*$k3$EEw}#6`SaIR7jEpo`BVGx zME&p&98OoxMa}8sbY3c+qRu2Q){nfD6RNo>o$vR-%t6< z|7Xvhl?~c!YW8f#j}xi2(W78+ZPIAcmcQoy2fm+X=c`1aLmGuuy^@#)j2Lu=NoDPJU9KK<97`1ttz zb$c~u>%N*YQL914+a*=ap4&{w$aj&kFu%fX?-FyPb!~S_3X;;ibgX~rA3SrX>;s>B z|F`eo<;CVlznpqufyx8BobTFc>w?~#;9k3SZT!@CTve)9G#77PIE#DN`Yl^Zteo`w z^|CnqHTMc#GC#R_>(;H6GQzV%x0zo#$G&uT+dPiI9gbXOKR&pwTeM-nqVput8s`rc zOVyotd3o(4S20iOxn;=yx#*%|i7QxGjdS+HT936Xao0T+gAZN3p3^dK*79CML*e5` qm^#*Qv>(=gs$ZCNW{O>;@dtj1f<&8RK5xrFC99{apUXO@geCyD5q)g{ literal 0 HcmV?d00001 diff --git a/app/static/images/wg/dislike_.png b/app/static/images/wg/dislike_.png new file mode 100644 index 0000000000000000000000000000000000000000..0f8606df3fa5736842f24992ba048e8f5d439322 GIT binary patch literal 1177 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`1f)iIruq6Z zXaU(A3`~qd49p-UK*-RZ$-n|;Gcc$DX$A)71&j#U1x#>Rl?BWQHb|kx<+G1~hD2tD zM3hAM`dB6B=jtV<VstT4fPE4;bsH1+JHo@{EISEfi{E8w==W>t3(ll z+GC>+vK+}V5TAlYfnK%aveAbJn;n;A+(UK-2Bt}#E{-7)oNs5G&lV08IG%3Cshhhs zgo9JpwnE^%mQaRcQ{2_b`#Z$_wK#4qvHh~*fvRYfj_wV6hd+%?3Kj1?eNMOrX6R=v z{dZ%P!mY4LImaq5Y{`%R_O|~aJumOyPxTQpWg65NnJXtasNk7g~?~c-kmhH zk*s8Sesm{0~@$%Cx=bNLlCBSNwUN0mBu! zJ_m-9IMKGJ<_t48zm#*ZkrZpVwVaXT)a&#Jk>J+EpS%t(Z!KfLn&&WARomV@S-w5_ zYl3x}bb$N&_j}(qOsKxqpmV5PX3eRlX}3dSCs*HSU@Ja<-SUTv*p?gHtWIrF_`ZR$ z)4`-Ea^Aj^i>}?Y*q6TNi}SkoKN_}8lE3G=@ssF2Io_)bWv4kyr3Hij%()Wzz4n}T zjd#`Iou@+<|2`S>apkP%980=F;^!P&cW>+bJ#wMRQugs{FTOdD@v&KL-_AGNAEY%I z?D`eP@5KA}$+XJp#+?(z`*T@i=Cr+^&|RkOVzKAx3*EXCy9HU?Lb8N7j;!Zfzj4Nk zZF!ZQS1O7f80yM0`1Gf0WjX8H8(dialDSY%D{kFkqc!g9n0yTk0=5XfzI&sQ>78XJEd_lnKuK1$xGxu9a5ML(Nd;<9jQ+atP(^Zs{OOgtf`R{Q1d#6R}dAJ{GPXWP6J R)&mte44$rjF6*2UngF~~zXAXN literal 0 HcmV?d00001 diff --git a/app/static/images/wg/like.png b/app/static/images/wg/like.png new file mode 100644 index 0000000000000000000000000000000000000000..6f6e23204b47c3d7ce012203698c514c8b760b2b GIT binary patch literal 1209 zcmV;q1V;ObP)g(%glHnhqmQ*L5P7kOLR{-DUTTo?XQDb51J{J~@j*i~rxdr24ylo*z5To!WFF4B!H}LYm;cvm0 z4rak>?HwH*GIbgoW>J4)912JLLEM61bnh_YYiZB196^kNboe-@$Jijwx`~agHZ|8w z>9Iiczsy9JySo)6qeH`=Kc#aD=w|z!)=8 zPwpuups<2SG?&;Io%S&bYeA2I%3+0&J@v`&4*wE0>9OF<}L3|-I zh}HVkak$LkKy7WU^|j6~x3shj@Juf-#@Y)Shr$YS`wV-2QX6wjSf6JmVzc#OzR0Hs zvsN-qS@q#j;5OS^HxeB+i}5LxX_5^=kUbF8F-I81*)gnaTM;syt_-L0iUUwnyetU?^~wkNipvUnQ~H!cswrW*U$Pg#BEXE%~lZi zVY#3`lt$Fgi9{kdK#w302)qW2RaI5Rs0)LoOu-_)noqfG&2|!+K7|T)<8@lk`%iHA z+TB^}g{>g@UG-Q*oQ=;aL8S_@tZY~{b)$2oMI%T_N5`w*E$WCrwsUgBe56Od1P z3C|egAYWsg0)-VMZ7j0?;T0hNw5Q6OA@UV44anj78BhHV-UDho+S}XrYLL%4f~1k5 zTmz;vS~5C%L0iZgTTJ_JAWE{;w96=MCq96G2EGaGnS`HX^ckRH74Np|hR5u`mB zt;0NQE@;B?U%{I}GLcBEqR#~CT%j^nxY_& zE2v;^kCi0u>+I~jfbb(A1-7=fw%+#g_;V5DCGmKD9s>XX|NqD5JoEqn00v1!K~w_( XagD@SMk?>f00000NkvXXu0mjfSei%3 literal 0 HcmV?d00001 diff --git a/app/static/images/wg/like_.png b/app/static/images/wg/like_.png new file mode 100644 index 0000000000000000000000000000000000000000..31c20ac959025e5388721f92b910d2b05334b676 GIT binary patch literal 788 zcmV+v1MB>WP)T2|hv4oe|n3bfq7lYSmSA zA&3wJg(RrpPFxf$EqS0tXp1F}ebhykKV@CE@+@&dbAY}k}NLWp?o|vT1cwX`T8fp)rY@$XYR-vNPP$u@6gISQEyZ+p{9!Q(B0DG zws20C|-7oF{z95vvcudUTuFJ5TI+DHn<66mx8okyN(`68`-4s z>fioZ?NZJH5qvoCF#WG*fcR;CriBq>CwHg}9`8#5p_Ow$L@D33^pX}vjGY4loE88^ zIR&)j8>qfD!ic#eK>SI0fn#6F0>CIofT}fYc)HfX>;SFjZq)rpAeu>=HPZnpeKc>D zxKVxtypPCd36q98Am5G5PXd@T$?e!pfHS^GMjY}?d+C7cS@sWN^#U8W8X!FJ506~7 z%54A&M6%Bb=^__qSPd^O_Sv;%K3lyAexJ<1wn zVVm0SkK|7IqPdvwb}lda+L08 { let data = res.data; try { - // 使用 JSONBig 解析响应数据,处理大数值 - data = JSONBig.parse(res.data); + data = JSONbigString.parse(res.data); } catch (e) { // JSONBig 解析失败时,使用原数据 + console.warn('JSONBig 解析失败:', e); + data = JSON.parse(res.data); } + console.debug('接口返回数据:', data); if (noVerify) reslove(data, res); else if (data.code == 200)