From bd57e65508781d967dedff5bb535dfefdb56e9e2 Mon Sep 17 00:00:00 2001 From: zxl <763096477@qq.com> Date: 星期四, 21 八月 2025 14:39:30 +0800 Subject: [PATCH] 抽奖活动,奖品 --- manager/src/views/activity-prize/index.vue | 661 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 568 insertions(+), 93 deletions(-) diff --git a/manager/src/views/activity-prize/index.vue b/manager/src/views/activity-prize/index.vue index d29b7aa..dc68f1e 100644 --- a/manager/src/views/activity-prize/index.vue +++ b/manager/src/views/activity-prize/index.vue @@ -75,7 +75,7 @@ <Button type="primary" size="small" - @click="changeStatus(row, row.enableStatus === 'on' ? '鍏抽棴' : '寮�鍚�')" + @click="publishPrizeActivity(row)" :loading="row.statusLoading" > {{row.enableStatus === 'on' ? '鍏抽棴' : '寮�鍚�'}} @@ -188,6 +188,7 @@ <Col span="24"> <FormItem label="娲诲姩鍥剧墖锛�" prop="activityImg"> <Upload + v-if="!imgTempUrl" :before-upload="(file) => handleBeforeUpload(file, 'content')" :format="['jpg','jpeg','png','gif']" :max-size="20480" @@ -195,11 +196,9 @@ accept="image/*" > <Button icon="ios-cloud-upload-outline">涓婁紶灏侀潰鍥剧墖</Button> - <div class="upload-tip">鏀寔鍥剧墖锛屾渶澶�20MB</div> </Upload> - <div v-if="activityImg" class="upload-file-info"> - <p>宸查�夋枃浠�: {{ activityImg.name }}</p> - <img :src="activityImg.activityImgUrl" alt="娲诲姩鍥剧墖" style="max-width: 100%; max-height: 200px;"> + <div v-else class="upload-file-info"> + <img :src="imgTempUrl" alt="娲诲姩鍥剧墖" class="preview-image-limit"> <Button type="text" @click="handleRemove('content')">鍒犻櫎</Button> </div> @@ -209,6 +208,7 @@ <Col span="24"> <FormItem label="娲诲姩灏侀潰锛�" prop="activityCover"> <Upload + v-if="!coverTempUrl" :before-upload="(file) => handleBeforeUpload(file, 'cover')" :format="['jpg','jpeg','png','gif']" :max-size="20480" @@ -216,11 +216,9 @@ accept="image/*" > <Button icon="ios-cloud-upload-outline">涓婁紶灏侀潰鍥剧墖</Button> - <div class="upload-tip">鏀寔鍥剧墖锛屾渶澶�20MB</div> </Upload> - <div v-if="activityCover" class="upload-file-info"> - <p>宸查�夋枃浠�: {{ activityCover.name }}</p> - <img :src="activityCover.activityCoverUrl" alt="娲诲姩鍥剧墖" style="max-width: 100%; max-height: 200px;"> + <div v-else class="upload-file-info"> + <img :src="coverTempUrl" alt="娲诲姩鍥剧墖" class="preview-image-limit"> <Button type="text" @click="handleRemove('cover')">鍒犻櫎</Button> </div> @@ -292,8 +290,8 @@ <Col span="24"> <div class="detail-item"> <label>娲诲姩鍥剧墖锛�</label> - <div v-if="detailData.activityImg" class="detail-image"> - <img :src="detailData.activityImg" alt="娲诲姩鍥剧墖" style="max-width: 100%; max-height: 200px;"> + <div v-if="detailData.activityImgUrl" class="detail-image"> + <img :src="detailData.activityImgUrl" alt="娲诲姩鍥剧墖" class="preview-image-limit"> </div> <span v-else>-</span> </div> @@ -301,10 +299,10 @@ <Col span="24"> <div class="detail-item"> <label>娲诲姩灏侀潰锛�</label> - <div v-if="detailData.activityCover" class="detail-image"> + <div v-if="detailData.activityCoverUrl" class="detail-image"> <img - :src="detailData.activityCover" alt="娲诲姩灏侀潰" - style="max-width: 100%; max-height: 200px;" + :src="detailData.activityCoverUrl" alt="娲诲姩灏侀潰" + class="preview-image-limit" > </div> <span v-else>-</span> @@ -313,23 +311,185 @@ <Col span="24"> <div class="detail-item"> <label>濂栧搧锛�</label> + <div style="width: 100%; overflow-y: auto; padding-bottom: 8px; box-sizing: border-box;height: 150px"> + <div v-if="detailData.prizes && detailData.prizes.length > 0" class="prize-list"> + <div v-for="(prize, index) in detailData.prizes" :key="index" class="prize-item"> + <div class="prize-header"> + <span class="prize-name">{{ prize.prizeName }}</span> + <Tag v-if="prize.prizeType"> + {{ replaceText(prize.prizeType) }} + </Tag> + </div> + <div class="prize-content"> + <p v-if="prize.prizeContent">{{ prize.prizeContent }}</p> + <Row :gutter="16" class="prize-info"> + <Col span="12"> + <span>鎬绘暟: {{ prize.prizeNum}}</span> + </Col> + <Col span="12"> + <span>鍓╀綑: + <span> + {{ prize.remainNum }} + </span> + </span> + </Col> + <Col span="12"> + <span>姒傜巼: {{ prize.probability}}%</span> + </Col> + </Row> + </div> + </div> + </div> + <div v-else class="no-prize"> + <span>鏆傛棤濂栧搧淇℃伅</span> + </div> + </div> + + </div> </Col> </Row> </div> </Modal> + + <Modal + v-model="prizeSettingShow" + title="濂栧搧璁剧疆" + @on-cancel="prizeSettingModelClose" + width="1200" + :mask-closable="false"> + <!-- 濂栧搧閮ㄥ垎 --> + + + <Form ref="activityPrizeForm" :label-width="100" > + <Col span="24"> + <FormItem label="濂栧搧鍒楄〃:"> + <Table + :loading="prizeLoading" + border + :columns="prizeColumns" + :data="prizeList" + ref="table" + class="prize-table" + > + <template slot-scope="{ row }" slot="prizeCoverUrl"> + <img + :src="row.prizeCoverUrl" + alt="濂栧搧灏侀潰" + class="thumbnail" + > + </template> + <template slot-scope="{ row }" slot="action"> + <Button + @click="choicePrize(row)" + :disabled="isPrizeChosen(row.id)" + type="primary" + icon="md-add" + > + {{ isPrizeChosen(row.id) ? '宸叉坊鍔�' : '娣诲姞' }} + </Button> + </template> + </Table> + <Row type="flex" justify="end" class="page-footer"> + <Page + :current="prizeSearchForm.pageNumber" + :total="prizeTotal" + :page-size="prizeSearchForm.pageSize" + @on-change="prizeChangePage" + @on-page-size-change="prizeChangePageSize" + :page-size-opts="[10, 20, 50]" + size="small" + show-total + show-elevator + show-sizer + ></Page> + </Row> + </FormItem> + </Col> + <Col span="24"> + <FormItem label="宸查�夊鍝�:"> + <!-- 閬嶅巻宸查�夊鍝侊紝骞跺彲浠ヨ缃暟閲忕瓑灞炴�� --> + <Table + :data="choiceData" + :columns="choiceColumns" + border + style="margin-top: 10px;" + :loading="choiceLoading" + > + <!-- 濂栧搧鍥剧墖 slot --> + <template slot-scope="{ row }" slot="prizeCoverUrl"> + <img :src="row.prizeCoverUrl" alt="濂栧搧灏侀潰" style="width: 50px; height: 50px; object-fit: cover;"> + </template> + <!-- 鏁伴噺 slot --> + <template slot-scope="{ row, index }" slot="maxPreDay"> + <InputNumber + v-model="row.maxPreDay" + :min="1" + :max="999999" + placeholder="璇疯緭鍏ユ瘡鏃ユ渶澶т腑濂栨暟" + style="width: 100%" + @on-change="(val) => handleMaxPreDayChange(val, index)" + ></InputNumber> + </template> + <template slot-scope="{ row, index }" slot="prizeNum"> + <InputNumber + v-model="row.prizeNum" + :min="1" + :max="999999" + placeholder="璇疯緭鍏ユ瘡鏃ユ渶澶т腑濂栨暟" + style="width: 100%" + @on-change="(val) => handlePrizeNumChange(val, index)" + ></InputNumber> + </template> + + <!-- 姒傜巼 slot --> + <template slot-scope="{ row, index }" slot="prizeProbability"> + <Input + v-model="row.prizeProbability" + placeholder="0.01" + style="width: 100%" + @on-blur="(e) => handleProbabilityInput(e, index)" + @on-enter="(e) => handleProbabilityInput(e, index)" + ></Input> + </template> + + <!-- 鎿嶄綔 slot --> + <template slot-scope="{ row, index }" slot="action"> + <Button type="error" size="small" icon="md-close" @click="removePrize(index)">绉婚櫎</Button> + </template> + </Table> + <!-- 濡傛灉娌℃湁閫夋嫨浠讳綍濂栧搧鏃剁殑鎻愮ず --> + <div v-if="choiceData.length === 0" style="text-align: center; color: #999; padding: 20px;"> + 灏氭湭閫夋嫨浠讳綍濂栧搧 + </div> + + </FormItem> + </Col> + </Form> + <div slot="footer"> + <Button @click="prizeSettingModelClose">鍙栨秷</Button> + <Button type="primary" :loading="choiceSubmitLoading" @click="choiceSubmit">鎻愪氦</Button> + </div> + </Modal> + </Card> </div> </template> <script> import { + getPage as getPrizePage +} from '@/api/prize.js' +import { getPage, detail, edit, add, - del + del, + addActivityRefPrizeList, + getActivityRefPrizeByActivityId, + publishPrizeActivity } from '@/api/activity-prize.js' import {delByKey, uploadFileByLmk} from "../../api/common"; @@ -338,6 +498,112 @@ data() { return { + //濂栧搧璁剧疆寮圭獥 + choiceLoading:false, + choiceSubmitLoading:false, + prizeTotal:0, + choiceData:[], + choiceColumns:[ + { + title: '濂栧搧鍥剧墖', + slot: 'prizeCoverUrl', + width: 80, + align: 'center' + }, + { + title: '濂栧搧鍚嶇О', + key: 'prizeName', + minWidth: 120 + }, + { + title: '濂栧搧绫诲瀷', + slot: 'prizeType', + width: 100, + render: (h, params) => { + if (params.row.prizeType === "coupon") { + return h("Tag", {props: {color: "red"}}, "浼樻儬鍒�"); + } else { + return h("Tag", {props: {color: "purple"}}, "鏈煡"); + } + } + }, + { + title: '姣忔棩鏈�澶т腑濂栨暟', + slot: 'maxPreDay', + width: 120 + }, + { + title: '鏁伴噺', + slot: 'prizeNum', + width: 120 + }, + { + title: '涓皢姒傜巼涓嶈兘涓虹┖', + slot: 'prizeProbability', + width: 120 + }, + { + title: '鎿嶄綔', + slot: 'action', + width: 80, + align: 'center' + } + ], + + prizeLoading:false, + prizeList:[], + prizeSettingShow:false, + prizeColumns:[ + { + title: '濂栧搧灏侀潰', + key: 'prizeCoverUrl', + slot:'prizeCoverUrl', + align: 'center', + minWidth: 100, + }, + { + title: '濂栧搧鍚嶇О', + key: 'prizeName', + minWidth: 100, + }, + { + title: '濂栧搧绫诲瀷', + key: 'prizeType', + minWidth: 100, + render: (h, params) => { + if (params.row.prizeType === "coupon") { + return h("Tag", {props: {color: "red"}}, "浼樻儬鍒�"); + } else { + return h("Tag", {props: {color: "purple"}}, "鏈煡"); + } + } + }, + { + title: '濂栧搧鍐呭', + key: 'prizeContent', + minWidth: 100, + }, + { + title: '濂栧搧鎻忚堪', + key: 'prizeDes', + minWidth: 100, + }, + { + title:'鎿嶄綔', + slot: 'action', + width: 200, + align:'center', + fixed:'right' + } + ], + activityPrizeId:null, + prizeSearchForm:{ + prizeName:'', + prizeType:'', + pageSize:10, + pageNumber:1, + }, + infoModalShow:false, detailData: {}, modelShow:false, @@ -462,11 +728,14 @@ activityName:'', endTime:'', beginTime:'', - }, submitLoading:false, activityCover:null, activityImg:null, + + coverTempUrl:null, + imgTempUrl:null, + } }, // 鍦ㄧ粍浠跺垱寤哄墠娉ㄥ唽 @@ -477,6 +746,125 @@ this.init(); }, methods: { + handleProbabilityInput(event, index) { + const inputValue = event.target.value; + let numericValue = parseFloat(inputValue); + + if (isNaN(numericValue)) { + this.choiceData[index].prizeProbabilityDisplay = '0.01'; + this.choiceData[index].prizeProbability = 0.01; + this.$Message.warning('璇疯緭鍏ユ湁鏁堢殑鏁板瓧'); + return; + } + + // 闄愬埗鑼冨洿 + if (numericValue < 0.01) { + numericValue = 0.01; + this.$Message.warning('涓姒傜巼涓嶈兘灏忎簬0.01'); + } else if (numericValue > 100) { + numericValue = 100; + this.$Message.warning('涓姒傜巼涓嶈兘澶т簬100'); + } + + // 淇濇寔2浣嶅皬鏁� + const fixedValue = parseFloat(numericValue.toFixed(2)); + this.choiceData[index].prizeProbabilityDisplay = fixedValue.toString(); + this.choiceData[index].prizeProbability = fixedValue; + + // 鏇存柊鍚庣瀛楁 + this.choiceData[index].probability = (fixedValue / 100).toFixed(4); + }, + choiceSubmit(){ + addActivityRefPrizeList(this.activityPrizeId,this.choiceData).then(res =>{ + if (res.code === 200){ + this.$Message.success(res.msg) + this.prizeSettingModelClose() + }else{ + this.$Message.error(res.msg) + } + }) + }, + + // 鏍煎紡鍖栧鍝佺被鍨� + replaceText(type) { + console.log(type) + if (type === "coupon") { + return "浼樻儬鍒�"; + } + return type; // 濡傛灉涓嶆槸鐩爣璇嶏紝杩斿洖鍘熸枃鏈� + }, + + // 鏁伴噺鍙樺寲澶勭悊 + handlePrizeNumChange(value, index) { + if (value === null || value < 1) { + this.choiceData[index].prizeNum = 1; + this.$Message.warning('鏁伴噺涓嶈兘灏忎簬1'); + } else { + this.choiceData[index].prizeNum = value; + } + }, + // 鏁伴噺鍙樺寲澶勭悊 + handleMaxPreDayChange(value, index) { + if (value === null || value < 1) { + this.choiceData[index].maxPreDay = 1; + this.$Message.warning('鏁伴噺涓嶈兘灏忎簬1'); + } else { + this.choiceData[index].maxPreDay = value; + } + }, + + // 绉婚櫎宸查�夊鍝� + removePrize(index) { + this.choiceData.splice(index, 1); + this.$Message.info('宸茬Щ闄ゅ鍝�'); + }, + // 妫�鏌ュ鍝佹槸鍚﹀凡琚�夋嫨 + isPrizeChosen(prizeId) { + return this.choiceData.some(item => item.id === prizeId); + }, + choicePrize(row){ + //鍒ゆ柇鏁扮粍闀垮害 + if(this.choiceData.length >= 5){ + this.$Message.warning("鏈�澶氭坊鍔�5涓鍝�") + return; + } + if (this.isPrizeChosen(row.id)){ + this.$Message.warning("宸叉坊鍔�") + return; + } + this.choiceLoading = true; + + const prizeToAdd = { + prizeCoverUrl:row.prizeCoverUrl, + prizeType: row.prizeType, + prizeName: row.prizeName, + prizeNum: 1, // 榛樿鏁伴噺涓�1 + maxPreDay:1, + prizeProbability:0.01, + prizeId:row.id, + prizeContent:row.prizeContent + // 鍙互娣诲姞鍏朵粬鎵╁睍灞炴�э紝濡傦細 + // sort: this.choiceData.length + 1 // 鎺掑簭 + }; + this.choiceData.push(prizeToAdd); + this.choiceLoading = false; + this.$Message.success('娣诲姞鎴愬姛锛�'); + + }, + getPrizeList(){ + this.prizeLoading = true; + getPrizePage(this.prizeSearchForm).then(res =>{ + this.prizeLoading = false; + if (res.code === 200){ + this.prizeList = res.data; + this.prizeTotal = res.total + }else { + this.$Message.error(res.msg) + } + }) + }, + + //瑙勫垯 validateBeginTime(rule, value, callback) { console.log("瑙﹀彂楠岃瘉") // 鏍¢獙蹇呭~ @@ -503,9 +891,35 @@ } callback(); // 楠岃瘉閫氳繃 }, + + //濂栧搧璁剧疆 setPrize(row){ + //鍒ゆ柇鏄惁鍚姩锛岃嫢鍚姩鍒欙紝鏃犳硶缂栬緫 + if("on" === row.enableStatus){ + this.$Message.error("鎶藉宸插紑鍚紝涓嶈兘缂栬緫!") + return + } + + this.activityPrizeId = row.id; + this.getPrizeList(); + this.prizeSettingShow = true; + + this.choiceLoading = true; + getActivityRefPrizeByActivityId(row.id).then(res =>{ + this.choiceLoading = false; + if (res.code === 200){ + this.choiceData = res.data + } + + }) }, + prizeSettingModelClose(){ + this.activityPrizeId = null; + this.prizeSettingShow = false; + this.choiceData = []; + }, + //鏂囨湰杞崲 formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') { if (!date) return ''; @@ -534,87 +948,70 @@ this.getPage() }, handleBeforeUpload(file,type){ - if ("content" === type){ - this.activityImg = file + if("content" === type){ + this.activityImg = file; + this.imgTempUrl = URL.createObjectURL(file); + return false; + }else if ("cover" === type){ + this.activityCover = file; + this.coverTempUrl = URL.createObjectURL(file); + return false; + } + }, + // 鍒犻櫎鏂囦欢 + handleRemove(type) { + if ('content' === type){ + this.activityImg = null; + this.imgTempUrl = null; + + }else if ('cover' === type){ + this.activityCover = null; + this.coverTempUrl = null; + } + }, + + async uploadFileByLmk(){ + if (this.activityImg){ this.submitLoading = true const formData = new FormData() formData.append('file', this.activityImg) - - uploadFileByLmk(formData).then(res => { + await uploadFileByLmk(formData).then(res => { this.submitLoading = false if (res.code === 200) { this.activityFrom.activityImg = res.data.fileKey; - this.activityImg.activityImgUrl = res.data.url; - this.$Message.success('涓婁紶鎴愬姛') + // this.$Message.success('涓婁紶鎴愬姛') }else{ - this.$Message.error(res.msg) + // this.$Message.error(res.msg) } }).catch(() => { this.submitLoading = false }) - }else if ("cover" === type){ - this.activityCover = file + } + if (this.activityCover){ this.submitLoading = true const formData = new FormData() formData.append('file', this.activityCover) - uploadFileByLmk(formData).then(res => { + await uploadFileByLmk(formData).then(res => { this.submitLoading = false if (res.code === 200) { this.activityFrom.activityCover = res.data.fileKey - this.activityCover.activityCoverUrl = res.data.url; - this.$Message.success('涓婁紶鎴愬姛') + // this.$Message.success('涓婁紶鎴愬姛') }else{ - this.$Message.error(res.msg) + // this.$Message.error(res.msg) } }).catch(() => { this.submitLoading = false }) } - - }, - // 鍒犻櫎鏂囦欢 - handleRemove(type) { - if ("content" === type){ - //鐐瑰嚮鍏抽棴绐楀彛鏃剁‘淇濇枃浠跺凡琚竻闄� - if (this.activityImg === null) { - return; - } - if (!this.activityFrom.activityImg) { - this.activityImg = null - return - } - delByKey(this.activityFrom.activityImg).then(res => { - if (res.code === 200) { - this.activityImg = null - this.activityFrom.activityImg = '' - }else{ - this.$Message.error(res.msg) - } - }) - }else if ("cover" === type){ - if (this.activityCover === null) { - return; - } - if (!this.activityFrom.activityCover) { - this.activityCover = null - return - } - delByKey(this.activityFrom.activityCover).then(res => { - if (res.code === 200) { - this.activityCover = null - this.activityFrom.activityCover = '' - }else{ - this.$Message.error(res.msg) - } - }) + async saveOrUpdate(){ + if (this.activityFrom.maxPrize < this.activityFrom.prizeNum){ + this.$Message.error("鍒濆鍖栨鏁板洜灏忎簬鎴栫瓑浜庢渶澶ф娊濂栨鏁�") + return } + await this.uploadFileByLmk(); - - - }, - saveOrUpdate(){ const submitData = { ...this.activityFrom, beginTime: this.formatDate(this.activityFrom.beginTime, 'YYYY-MM-DD HH:mm:ss'), @@ -629,7 +1026,7 @@ this.submitLoading = false if (res.code === 200) { this.$Message.success(res.msg) - this.modelClose() + this.modelShow = false; this.getPage() }else{ this.$Message.error(res.msg) @@ -646,8 +1043,6 @@ modelClose(){ this.modelShow = false this.submitLoading = false - this.handleRemove("content"); - this.handleRemove("cover"); this.$refs.form.resetFields() }, getPage(){ @@ -656,6 +1051,7 @@ this.loading = false; if (res.code === 200){ this.activityList = res.data; + this.total = res.total; }else { this.$Message.error(res.msg) } @@ -664,6 +1060,13 @@ detail(row){ this.infoModalShow = true; this.detailData = {...row}; + getActivityRefPrizeByActivityId(row.id).then(res=>{ + if (res.code ===200){ + this.$set(this.detailData,'prizes', res.data); + } + }) + console.log(this.detailData) + }, openEdit(row){ this.modelShow = true; @@ -680,6 +1083,9 @@ activityCover:row.activityCover, enableStatus:row.enableStatus, } + this.coverTempUrl = row.activityCoverUrl; + this.imgTempUrl = row.activityImgUrl; + }, handleSearch(type,value){ @@ -691,8 +1097,13 @@ this.getPage() }, openAdd(){ + this.$refs.form.resetFields() this.modelShow = true; this.modelTitle = "鏂板娲诲姩"; + this.coverTempUrl = null; + this.prizeCover=null; + this.prizeImg = null; + this.imgTempUrl = null; }, delById(row){ del(row.id).then(res=>{ @@ -718,8 +1129,24 @@ this.searchForm.pageNumber = page this.getPage() }, - changeStatus(){ - + prizeChangePage(){ + this.prizeSearchForm.pageNumber = 1 + this.prizeSearchForm.pageSize = pageSize + this.getPrizeList() + }, + prizeChangePageSize(){ + this.prizeSearchForm.pageNumber = page + this.getPrizeList() + }, + publishPrizeActivity(row){ + publishPrizeActivity(row.id).then(res =>{ + if (res.code === 200){ + this.$Message.success(res.msg) + }else{ + this.$Message.error(res.msg) + } + }) + this.getPage() }, }, @@ -780,12 +1207,6 @@ } } .activity-table { - .media-container { - display: flex; - justify-content: center; - align-items: center; - height: 100px; - .thumbnail { max-width: 100%; max-height: 100%; @@ -798,21 +1219,32 @@ box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); } } + .action-btns { + display: flex; + flex-wrap: wrap; + justify-content: center; - .video-player { - max-width: 100%; - max-height: 100px; - background: #000; - } - - .text-cover { - padding: 8px; - background: #f8f8f9; - border-radius: 4px; - max-width: 100%; - word-break: break-all; + .ivu-btn { + margin: 4px; + font-size: 12px; + padding: 2px 6px; + min-width: 60px; } } +} +.prize-table { + .thumbnail { + max-width: 100px; + max-height: 100px; + object-fit: contain; + cursor: pointer; + transition: all 0.3s; + + &:hover { + transform: scale(1.05); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); + } + } .action-btns { display: flex; @@ -827,4 +1259,47 @@ } } } +.preview-image-limit{ + max-width: 100%; + max-height: 200px; + object-fit: contain; + border-radius: 4px; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + display: block; +} +//璇︽儏鍟嗗搧鏍峰紡 +.prize-list { + margin-top: 10px; + max-height: 300px; + overflow-y: auto; +} + +.prize-item { + padding: 12px; + border: 1px solid #e8eaec; + border-radius: 4px; + margin-bottom: 10px; + background: #f8f9fa; +} +.prize-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.prize-name { + font-weight: bold; + color: #17233d; +} + +.prize-content { + font-size: 13px; +} + +.prize-info { + margin-top: 8px; + color: #808695; +} + </style> -- Gitblit v1.8.0