first commit

This commit is contained in:
2026-01-08 14:58:16 +08:00
commit 556e5d64aa
9575 changed files with 1621095 additions and 0 deletions
@@ -0,0 +1,443 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava :edit_scroll="false" ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
:clearable="false"
placeholder="请选择年度"
style="width: 100%"
type="year"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="我的福利"></table-tool>
<el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table"
row-key="id"
style="width: 100%"
v-loading="tableLoading"
>
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:key="column.prop"
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
align="center"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='choiceTime'">
<i class="el-icon-time"></i>
&ensp; {{$moment(row.choiceTimeStart).format('YYYY/MM/DD HH:mm')}}
<span>- {{$moment(row.choiceTimeEnd).format('YYYY/MM/DD HH:mm')}}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='isChoose'">
<span class="text-primary" v-if="row.isChoose">已选择</span>
<span class="text-danger" v-else>未选择</span>
</template>
<template scope="{row}" v-else-if="column.prop=='gist_list'">
<template v-if="row.gist_list">{{row.gist_list}}</template>
</template>
<template scope="{row}" v-else-if="column.prop=='receiveAddress'">
<span v-if="row.receiveAddress">{{row.receiveAddress}}</span>
<span v-else>暂无</span>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作" prop="userOnline" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<!-- <el-button :disabled="!row.courierNumber" @click="openEvaluate(row)" size="mini" type="primary">评价</el-button>-->
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
<select-view ref="selectViewRef"></select-view>
</div>
<script nonce="${cspNonce!}">
<!--#include('selectView.js'){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
pageForm: {
year: moment().format("YYYY"),
searchName: "username"
},
tableColumns: [
{ prop: "year", label: "年度" },
{ prop: "name", label: "项目名称" },
{ prop: "choiceTime", label: "选择时间" },
{ prop: "isChoose", label: "是否选择" },
{ prop: "gist_list", label: "所选福利" }
// { prop: "receiveAddress", label: "收货地址" }
// { prop: "courierNumber", label: "快递单号", sortable: true }
]
}
},
components: {
"select-view": selectView
},
methods: {
async openView(row) {
this.$refs.selectViewRef.onOpen(row.id)
}
},
async created() {
this.pageData()
}
})
</script>
<style>
.welfare-select-view-dialog .el-dialog__body {
padding: 20px;
}
/* 项目信息卡片 */
.project-info-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
margin-bottom: 16px;
overflow: hidden;
}
.project-info-header {
padding: 14px 16px;
border-bottom: 1px solid #EBEEF5;
font-size: 16px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
background: linear-gradient(135deg, #f8f9fb 0%, #fff 100%);
}
.project-info-header i {
margin-right: 8px;
color: var(--color-primary);
font-size: 18px;
}
.project-info-content {
padding: 0;
}
.info-item {
display: flex;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #EBEEF5;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
width: 100px;
color: #606266;
font-weight: 500;
flex-shrink: 0;
}
.info-value {
flex: 1;
color: #303133;
}
/* 选择卡片 */
.my-selections-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
overflow: hidden;
}
.selections-header {
padding: 14px 16px;
border-bottom: 1px solid #EBEEF5;
font-size: 16px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
background: linear-gradient(135deg, #f8f9fb 0%, #fff 100%);
}
.selections-header i {
margin-right: 8px;
color: var(--color-primary);
font-size: 18px;
}
.selections-content {
padding: 16px;
}
.selection-item {
display: flex;
align-items: center;
padding: 12px;
border-radius: 6px;
margin-bottom: 12px;
background: #f8f9fb;
transition: all 0.3s;
}
.selection-item:last-child {
margin-bottom: 0;
}
.selection-item:hover {
transform: translateX(4px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.selection-item-image {
width: 80px;
height: 80px;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.selection-item-image .el-image {
width: 100%;
height: 100%;
}
.image-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #f5f7fa;
color: #909399;
font-size: 24px;
}
.selection-item-info {
flex: 1;
padding: 0 16px;
display: flex;
flex-direction: column;
}
.selection-item-name {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 6px;
}
.selection-item-meta {
margin-bottom: 8px;
}
.selection-item-count, .selection-item-time {
font-size: 13px;
color: #606266;
margin-bottom: 4px;
}
.selection-item-actions {
margin-top: 4px;
}
.detail-btn {
padding: 4px 8px;
font-size: 12px;
color: var(--color-primary);
background: #ecf5ff;
border-radius: 4px;
}
.detail-btn:hover {
background: #dbecff;
color: #3a8ee6;
}
.detail-btn i {
margin-right: 4px;
}
.count-value {
color: var(--color-primary);
font-weight: 600;
background: #ecf5ff;
padding: 2px 6px;
border-radius: 10px;
font-size: 12px;
}
.selection-item-status {
flex-shrink: 0;
width: 70px;
text-align: right;
}
.no-selections {
padding: 40px 0;
text-align: center;
color: #909399;
font-size: 14px;
display: flex;
flex-direction: column;
align-items: center;
}
.no-selections i {
font-size: 40px;
margin-bottom: 10px;
color: #C0C4CC;
}
/* 详情弹窗样式 */
.welfare-detail-dialog .el-dialog__body {
padding: 0;
}
.welfare-detail-content {
padding: 20px;
}
.detail-header {
display: flex;
margin-bottom: 20px;
}
.detail-image {
width: 120px;
height: 120px;
border-radius: 6px;
overflow: hidden;
flex-shrink: 0;
margin-right: 20px;
}
.detail-image .el-image {
width: 100%;
height: 100%;
}
.detail-title {
flex: 1;
}
.detail-title h3 {
margin: 0 0 12px 0;
font-size: 18px;
color: #303133;
}
.detail-meta {
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-count, .detail-time {
display: flex;
align-items: center;
font-size: 14px;
color: #606266;
}
.detail-count i, .detail-time i {
margin-right: 6px;
color: #909399;
}
.detail-divider {
height: 1px;
background: #EBEEF5;
margin: 20px 0;
}
.detail-description {
color: #606266;
line-height: 1.6;
}
/* 富文本内容样式 */
.rich-text-content {
overflow-x: hidden;
word-break: break-word;
}
.rich-text-content img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 10px 0;
}
.rich-text-content p {
margin: 8px 0;
line-height: 1.6;
}
.rich-text-content a {
color: var(--color-primary);
text-decoration: none;
}
.rich-text-content a:hover {
text-decoration: underline;
}
.rich-text-content ul, .rich-text-content ol {
padding-left: 20px;
margin: 10px 0;
}
.rich-text-content blockquote {
padding: 10px 15px;
border-left: 4px solid #EBEEF5;
background: #f8f9fb;
margin: 10px 0;
color: #606266;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,523 @@
const selectView = {
template: /*language=HTML*/ `
<el-dialog title="我的福利选择" :visible.sync="visible" width="700px" append-to-body custom-class="welfare-select-view-dialog">
<div v-loading="loading">
<!-- 项目基本信息 -->
<div class="project-info-card">
<div class="project-info-header">
<i class="el-icon-s-flag"></i>
<span>项目基本信息</span>
</div>
<div class="project-info-content">
<div class="info-item">
<div class="info-label">项目名称</div>
<div class="info-value">{{ projectInfo.name }}</div>
</div>
<div class="info-item">
<div class="info-label">选择时间</div>
<div class="info-value">{{ projectInfo.choiceTimeStart }} 至 {{ projectInfo.choiceTimeEnd }}</div>
</div>
<div class="info-item">
<div class="info-label">发放时间</div>
<div class="info-value">{{ projectInfo.provideTimeStart }} 至 {{ projectInfo.provideTimeEnd }}</div>
</div>
<div class="info-item">
<div class="info-label">发放地点</div>
<div class="info-value">{{ projectInfo.provideAddress }}</div>
</div>
</div>
</div>
<!-- 联系信息 -->
<div class="project-info-card">
<div class="project-info-header">
<i class="el-icon-user"></i>
<span>联系信息</span>
</div>
<div class="project-info-content">
<div class="info-item">
<div class="info-label">联系电话</div>
<div class="info-value">{{ mergedSelections[0]?.mobile || '暂无' }}</div>
</div>
<div class="info-item">
<div class="info-label">收货地址</div>
<div class="info-value">{{ mergedSelections[0]?.receiveAddress || '暂无' }}</div>
</div>
</div>
</div>
<!-- 我的选择 -->
<div class="my-selections-card">
<div class="selections-header">
<i class="el-icon-shopping-cart-full"></i>
<span>我的选择</span>
</div>
<div v-if="mergedSelections.length > 0" class="selections-content">
<div class="selection-item" v-for="item in mergedSelections" :key="item.id">
<div class="selection-item-image">
<el-image
:src="item.imgUrl || '/static/images/default-welfare.png'"
fit="cover"
:preview-src-list="item.imgUrl ? [item.imgUrl] : []">
<div slot="error" class="image-placeholder">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</div>
<div class="selection-item-info">
<div class="selection-item-name">{{ item.optionName }}</div>
<div class="selection-item-meta">
<div class="selection-item-count">
<span>数量:</span>
<span class="count-value">{{ item.selectNum }}</span>
</div>
<div class="selection-item-time">
<span>选择时间:</span>
<span>{{ item.selectTime }}</span>
</div>
</div>
<div class="selection-item-actions">
<el-button
type="text"
size="small"
class="detail-btn"
@click="showOptionDetail(item)">
<i class="el-icon-view"></i> 查看详情
</el-button>
</div>
</div>
<div class="selection-item-status">
<el-tag size="small" type="success">已选择</el-tag>
</div>
</div>
</div>
<div v-else class="no-selections">
<i class="el-icon-warning-outline"></i>
<span>您还未选择任何福利项目</span>
</div>
</div>
</div>
<!-- 详情弹窗 -->
<el-dialog
title="福利详情"
:visible.sync="detailDialogVisible"
width="650px"
append-to-body
custom-class="welfare-detail-dialog">
<div class="welfare-detail-content" v-if="currentOption">
<!-- <div class="detail-header">-->
<!-- <div class="detail-image">-->
<!-- <el-image -->
<!-- :src="currentOption.imgUrl || '/static/images/default-welfare.png'" -->
<!-- fit="cover">-->
<!-- <div slot="error" class="image-placeholder">-->
<!-- <i class="el-icon-picture-outline"></i>-->
<!-- </div>-->
<!-- </el-image>-->
<!-- </div>-->
<!-- <div class="detail-title">-->
<!-- <h3>{{ currentOption.optionName }}</h3>-->
<!-- <div class="detail-meta">-->
<!-- <span class="detail-count">-->
<!-- <i class="el-icon-shopping-cart-2"></i> -->
<!-- 数量: <span class="count-value">{{ currentOption.selectNum }}</span>-->
<!-- </span>-->
<!-- <span class="detail-time">-->
<!-- <i class="el-icon-time"></i> -->
<!-- 选择时间: {{ currentOption.selectTime }}-->
<!-- </span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="detail-divider"></div>-->
<div class="detail-description rich-text-content" v-html="currentOption.description"></div>
</div>
</el-dialog>
</el-dialog>
`,
data() {
return {
projectId: null,
visible: false,
loading: false,
projectInfo: {
name: "",
choiceTimeStart: "",
choiceTimeEnd: "",
provideTimeStart: "",
provideTimeEnd: "",
provideAddress: "",
options: []
},
selectedOptions: [],
detailDialogVisible: false,
currentOption: null
}
},
computed: {
mergedSelections() {
return this.selectedOptions.map((item) => {
const option = this.projectInfo.options?.find((opt) => opt.id === item.selectOptionId) || {}
return {
...item,
optionName: option.optionName || "未知选项",
imgUrl: option.imgUrl,
description: option.description
}
})
}
},
methods: {
onOpen(id) {
this.projectId = id
this.visible = true
this.loadData()
},
async loadData() {
this.loading = true
await this.getProjectInfo()
await this.getUserSelections()
this.loading = false
},
async getProjectInfo() {
const { code, data, msg } = await this.$axios.post("/platform/welfare/common/projectInfo", {
id: this.projectId
})
if (code === 0) {
this.projectInfo = data
}
},
async getUserSelections() {
const { code, data, msg } = await this.$axios.post("/platform/welfare/userSelect/getUserSelection", { projectId: this.projectId })
if (code === 0) {
this.selectedOptions = data || []
}
},
showOptionDetail(option) {
this.currentOption = option
this.detailDialogVisible = true
}
},
style: /*language=CSS*/ `
.welfare-select-view-dialog .el-dialog__body {
padding: 20px;
}
/* 项目信息卡片 */
.project-info-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
margin-bottom: 16px;
overflow: hidden;
}
.project-info-header {
padding: 14px 16px;
border-bottom: 1px solid #EBEEF5;
font-size: 16px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
background: linear-gradient(135deg, #f8f9fb 0%, #fff 100%);
}
.project-info-header i {
margin-right: 8px;
color: var(--color-primary);
font-size: 18px;
}
.project-info-content {
padding: 0;
}
.info-item {
display: flex;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #EBEEF5;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
width: 100px;
color: #606266;
font-weight: 500;
flex-shrink: 0;
}
.info-value {
flex: 1;
color: #303133;
}
/* 选择卡片 */
.my-selections-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
overflow: hidden;
}
.selections-header {
padding: 14px 16px;
border-bottom: 1px solid #EBEEF5;
font-size: 16px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
background: linear-gradient(135deg, #f8f9fb 0%, #fff 100%);
}
.selections-header i {
margin-right: 8px;
color: var(--color-primary);
font-size: 18px;
}
.selections-content {
padding: 16px;
}
.selection-item {
display: flex;
align-items: center;
padding: 12px;
border-radius: 6px;
margin-bottom: 12px;
background: #f8f9fb;
transition: all 0.3s;
}
.selection-item:last-child {
margin-bottom: 0;
}
.selection-item:hover {
transform: translateX(4px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.selection-item-image {
width: 80px;
height: 80px;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.selection-item-image .el-image {
width: 100%;
height: 100%;
}
.image-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #f5f7fa;
color: #909399;
font-size: 24px;
}
.selection-item-info {
flex: 1;
padding: 0 16px;
display: flex;
flex-direction: column;
}
.selection-item-name {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 6px;
}
.selection-item-meta {
margin-bottom: 8px;
}
.selection-item-count, .selection-item-time {
font-size: 13px;
color: #606266;
margin-bottom: 4px;
}
.selection-item-actions {
margin-top: 4px;
}
.detail-btn {
padding: 4px 8px;
font-size: 12px;
color: var(--color-primary);
background: #ecf5ff;
border-radius: 4px;
}
.detail-btn:hover {
background: #dbecff;
color: #3a8ee6;
}
.detail-btn i {
margin-right: 4px;
}
.count-value {
color: var(--color-primary);
font-weight: 600;
background: #ecf5ff;
padding: 2px 6px;
border-radius: 10px;
font-size: 12px;
}
.selection-item-status {
flex-shrink: 0;
width: 70px;
text-align: right;
}
.no-selections {
padding: 40px 0;
text-align: center;
color: #909399;
font-size: 14px;
display: flex;
flex-direction: column;
align-items: center;
}
.no-selections i {
font-size: 40px;
margin-bottom: 10px;
color: #C0C4CC;
}
/* 详情弹窗样式 */
.welfare-detail-dialog .el-dialog__body {
padding: 0;
}
.welfare-detail-content {
padding: 20px;
}
.detail-header {
display: flex;
margin-bottom: 20px;
}
.detail-image {
width: 120px;
height: 120px;
border-radius: 6px;
overflow: hidden;
flex-shrink: 0;
margin-right: 20px;
}
.detail-image .el-image {
width: 100%;
height: 100%;
}
.detail-title {
flex: 1;
}
.detail-title h3 {
margin: 0 0 12px 0;
font-size: 18px;
color: #303133;
}
.detail-meta {
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-count, .detail-time {
display: flex;
align-items: center;
font-size: 14px;
color: #606266;
}
.detail-count i, .detail-time i {
margin-right: 6px;
color: #909399;
}
.detail-divider {
height: 1px;
background: #EBEEF5;
margin: 20px 0;
}
.detail-description {
color: #606266;
line-height: 1.6;
}
/* 富文本内容样式 */
.rich-text-content {
overflow-x: hidden;
word-break: break-word;
}
.rich-text-content img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 10px 0;
}
.rich-text-content p {
margin: 8px 0;
line-height: 1.6;
}
.rich-text-content a {
color: var(--color-primary);
text-decoration: none;
}
.rich-text-content a:hover {
text-decoration: underline;
}
.rich-text-content ul, .rich-text-content ol {
padding-left: 20px;
margin: 10px 0;
}
.rich-text-content blockquote {
padding: 10px 15px;
border-left: 4px solid #EBEEF5;
background: #f8f9fb;
margin: 10px 0;
color: #606266;
}
`
}