This commit is contained in:
那些花儿
2025-06-20 09:24:39 +08:00
parent bfa9aba489
commit bc5eb03f7f
23 changed files with 1585 additions and 834 deletions
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<bean class="org.snaker.nutz.access.NutzAccess"/>
<bean class="org.snaker.nutz.access.NutzTransactionInterceptor"/>
<bean class="org.snaker.engine.access.dialect.MySqlDialect" />
<bean class="org.snaker.engine.impl.JuelExpression" />
</config>
@@ -0,0 +1,593 @@
<script>
module.exports = {
name: "index",
props: {
group: {
type: Object,
required: true
},
field_options: {
type: Array,
required: true
},
operator_options: {
type: Array,
default: () => [
{ label: "等于", value: "=" },
{ label: "不等于", value: "!=" },
{ label: "大于", value: ">" },
{ label: "小于", value: "<" },
{ label: "大于等于", value: ">=" },
{ label: "小于等于", value: "<=" },
{ label: "包含", value: "LIKE" },
{ label: "为空", value: "IS NULL" },
{ label: "不为空", value: "IS NOT NULL" },
{ label: "在列表中", value: "IN" },
{ label: "不在列表中", value: "NOT IN" },
{ label: "在范围内", value: "BETWEEN" }
]
},
can_remove: {
type: Boolean,
default: false
}
},
data() {
return {
fieldTypes: {}, // 存储字段类型信息
errors: [] // 存储验证错误
}
},
created() {
// 初始化字段类型信息
this.initFieldTypes()
},
methods: {
initFieldTypes() {
// 从field_options中提取字段类型信息
this.field_options.forEach((field) => {
if (field.type) {
this.fieldTypes[field.value] = field.type
} else {
// 默认为字符串类型
this.fieldTypes[field.value] = "string"
}
})
},
getFieldType(fieldName) {
return this.fieldTypes[fieldName] || "string"
},
addCondition() {
if (!this.group.conditions) {
this.$set(this.group, "conditions", [])
}
this.group.conditions.push({
field: "",
operator: "=",
value: "",
valid: false
})
this.validateAndEmitChange()
},
removeCondition(index) {
this.group.conditions.splice(index, 1)
this.validateAndEmitChange()
},
addGroup() {
if (!this.group.groups) {
this.$set(this.group, "groups", [])
}
this.group.groups.push({
logic: "AND",
conditions: [],
groups: []
})
this.validateAndEmitChange()
},
removeGroup(index) {
this.group.groups.splice(index, 1)
this.validateAndEmitChange()
},
isNullOperator(operator) {
return operator === "IS NULL" || operator === "IS NOT NULL"
},
isInOperator(operator) {
return operator === "IN" || operator === "NOT IN"
},
isBetweenOperator(operator) {
return operator === "BETWEEN"
},
validateCondition(condition) {
// 检查条件是否有效
if (!condition.field || !condition.operator) {
return false
}
// 对于IS NULL和IS NOT NULL操作符,不需要值
if (this.isNullOperator(condition.operator)) {
return true
}
// 对于其他操作符,需要值
return condition.value !== undefined && condition.value !== ""
},
validateGroup(group) {
let isValid = true
// 验证条件
if (group.conditions && group.conditions.length > 0) {
group.conditions.forEach((condition) => {
condition.valid = this.validateCondition(condition)
isValid = isValid && condition.valid
})
}
// 验证嵌套组
if (group.groups && group.groups.length > 0) {
group.groups.forEach((nestedGroup) => {
isValid = isValid && this.validateGroup(nestedGroup)
})
}
// 一个组至少需要一个条件或嵌套组才有效
if ((group.conditions && group.conditions.length > 0) || (group.groups && group.groups.length > 0)) {
return isValid
} else {
return false
}
},
formatValue(value, type) {
// 根据字段类型格式化值
if (value === null || value === undefined || value === "") {
return "NULL"
}
switch (type.toLowerCase()) {
case "number":
case "int":
case "integer":
case "float":
case "double":
case "decimal":
return value
case "date":
case "datetime":
case "time":
case "string":
default:
// 转义单引号
const escaped = String(value).replace(/'/g, "''")
return `'${escaped}'`
}
},
buildSql(group = this.group) {
let sql = []
// 处理条件
if (group.conditions && group.conditions.length > 0) {
group.conditions.forEach((condition) => {
if (condition.field && condition.operator) {
const fieldType = this.getFieldType(condition.field)
if (this.isNullOperator(condition.operator)) {
sql.push(`${condition.field} ${condition.operator}`)
} else if (this.isInOperator(condition.operator) && condition.value) {
// 处理IN操作符 - 假设值是以逗号分隔的列表
const values = condition.value
.split(",")
.map((v) => v.trim())
.filter((v) => v !== "")
.map((v) => this.formatValue(v, fieldType))
.join(", ")
if (values) {
sql.push(`${condition.field} ${condition.operator} (${values})`)
}
} else if (this.isBetweenOperator(condition.operator) && condition.value) {
// 处理BETWEEN操作符 - 假设值是以逗号分隔的两个值
const parts = condition.value.split(",").map((v) => v.trim())
if (parts.length === 2) {
const from = this.formatValue(parts[0], fieldType)
const to = this.formatValue(parts[1], fieldType)
sql.push(`${condition.field} BETWEEN ${from} AND ${to}`)
}
} else if (condition.value !== undefined && condition.value !== "") {
// 其他操作符
const formattedValue = this.formatValue(condition.value, fieldType)
sql.push(`${condition.field} ${condition.operator} ${formattedValue}`)
}
}
})
}
// 处理嵌套组
if (group.groups && group.groups.length > 0) {
group.groups.forEach((nestedGroup) => {
const nestedSql = this.buildSql(nestedGroup)
if (nestedSql) {
sql.push(`(${nestedSql})`)
}
})
}
// 用逻辑运算符连接所有条件
return sql.length > 0 ? sql.join(` ${group.logic} `) : ""
},
validateAndEmitChange() {
// 验证所有条件
const isValid = this.validateGroup(this.group)
// 发出变更事件
this.$emit("change", {
sql: this.buildSql(),
valid: isValid
})
},
getOperatorsByFieldType(fieldType) {
// 根据字段类型过滤可用的操作符
if (!fieldType) return this.operator_options
const type = fieldType.toLowerCase()
return this.operator_options.filter((op) => {
// 数值类型
if (['number', 'int', 'integer', 'float', 'double', 'decimal'].includes(type)) {
// 数值类型不应该使用LIKE操作符
return op.value !== 'LIKE'
}
// 日期类型
else if (['date', 'datetime', 'time'].includes(type)) {
// 日期类型不应该使用LIKE和IN操作符
return !['LIKE', 'IN', 'NOT IN'].includes(op.value)
}
// 字符串类型,支持所有操作符
return true
})
}
},
watch: {
group: {
handler: "validateAndEmitChange",
deep: true
},
field_options: {
handler: "initFieldTypes",
immediate: true
}
}
}
</script>
<template>
<div class="condition-builder">
<!-- 主逻辑选择和组操作 -->
<div class="condition-group-header">
<div class="logic-selector">
<span class="logic-label">匹配方式</span>
<el-radio-group v-model="group.logic" size="small" @change="validateAndEmitChange">
<el-radio-button label="AND">满足所有条件</el-radio-button>
<el-radio-button label="OR">满足任意条件</el-radio-button>
</el-radio-group>
</div>
<el-button v-if="can_remove" type="danger" size="mini" icon="el-icon-delete" @click="$emit('remove')" class="remove-group-btn">
删除组
</el-button>
</div>
<!-- 条件列表 -->
<div class="conditions-container">
<div
v-for="(condition, index) in group.conditions"
:key="'c-' + index"
class="condition-row"
:class="{ 'invalid-condition': condition.valid === false }"
>
<div class="condition-index">{{ index + 1 }}</div>
<el-select
v-model="condition.field"
filterable
placeholder="请选择字段"
size="small"
class="field-select"
@change="validateAndEmitChange"
>
<el-option v-for="field in field_options" :key="field.value" :label="field.label" :value="field.value">
<span>{{ field.label }}</span>
<span class="field-type-hint" v-if="field.type">({{ field.type }})</span>
</el-option>
</el-select>
<el-select v-model="condition.operator" placeholder="操作符" size="small" class="operator-select" @change="validateAndEmitChange">
<el-option
v-for="op in getOperatorsByFieldType(getFieldType(condition.field))"
:key="op.value"
:label="op.label"
:value="op.value"
></el-option>
</el-select>
<!-- 根据操作符类型和字段类型显示不同的输入控件 -->
<template v-if="!isNullOperator(condition.operator)">
<!-- 对于IN操作符显示标签输入框 -->
<el-input
v-if="isInOperator(condition.operator)"
v-model="condition.value"
placeholder="多个值用逗号分隔"
size="small"
class="value-input"
@change="validateAndEmitChange"
></el-input>
<!-- 对于BETWEEN操作符显示两个输入框 -->
<div v-else-if="isBetweenOperator(condition.operator)" class="between-inputs">
<el-input
v-model="condition.value"
placeholder="起始值,结束值"
size="small"
class="value-input"
@change="validateAndEmitChange"
></el-input>
</div>
<!-- 对于其他操作符根据字段类型显示不同的输入控件 -->
<template v-else>
<!-- 数字类型 -->
<el-input
v-if="['number', 'int', 'integer', 'float', 'double', 'decimal'].includes(getFieldType(condition.field))"
v-model.number="condition.value"
placeholder="请输入数值"
size="small"
class="value-input"
type="number"
@change="validateAndEmitChange"
></el-input>
<!-- 日期类型 -->
<el-date-picker
v-else-if="getFieldType(condition.field) === 'date'"
v-model="condition.value"
type="date"
placeholder="选择日期"
size="small"
class="value-input"
value-format="yyyy-MM-dd"
@change="validateAndEmitChange"
></el-date-picker>
<!-- 日期时间类型 -->
<el-date-picker
v-else-if="getFieldType(condition.field) === 'datetime'"
v-model="condition.value"
type="datetime"
placeholder="选择日期时间"
size="small"
class="value-input"
value-format="yyyy-MM-dd HH:mm:ss"
@change="validateAndEmitChange"
></el-date-picker>
<!-- 时间类型 -->
<el-time-picker
v-else-if="getFieldType(condition.field) === 'time'"
v-model="condition.value"
placeholder="选择时间"
size="small"
class="value-input"
value-format="HH:mm:ss"
@change="validateAndEmitChange"
></el-time-picker>
<!-- 默认为字符串类型 -->
<el-input
v-else
v-model="condition.value"
placeholder="请输入值"
size="small"
class="value-input"
@change="validateAndEmitChange"
></el-input>
</template>
</template>
<!-- 空值占位使布局保持一致 -->
<div v-else class="value-placeholder"></div>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeCondition(index)" class="remove-btn"></el-button>
</div>
<!-- 空条件提示 -->
<div class="empty-condition-hint" v-if="!group.conditions || group.conditions.length === 0">
<i class="el-icon-info"></i>
请添加筛选条件
</div>
</div>
<!-- 嵌套条件组 -->
<div v-for="(nestedGroup, index) in group.groups" :key="'g-' + index" class="nested-group">
<div class="nested-group-header">
<span class="nested-group-title">子条件组 {{ index + 1 }}</span>
</div>
<condition-group
:group="nestedGroup"
:field_options="field_options"
:operator_options="operator_options"
:can_remove="true"
@remove="removeGroup(index)"
@change="validateAndEmitChange"
></condition-group>
</div>
<!-- 操作按钮区 -->
<div class="condition-actions">
<el-button type="primary" size="small" icon="el-icon-plus" @click="addCondition">添加条件</el-button>
<el-button type="success" size="small" icon="el-icon-folder-add" @click="addGroup">添加条件组</el-button>
</div>
<!-- SQL预览 -->
<div class="sql-preview" v-if="buildSql()">
<div class="sql-preview-header">
<div class="sql-preview-title">条件预览:</div>
</div>
<el-input type="textarea" :value="buildSql()" readonly :rows="2" class="sql-preview-content"></el-input>
</div>
</div>
</template>
<style scoped>
.condition-builder {
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 15px;
margin-bottom: 15px;
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.condition-group-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #ebeef5;
}
.logic-label {
margin-right: 10px;
color: #606266;
}
.conditions-container {
padding: 5px;
margin-bottom: 15px;
}
.condition-row {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 8px;
background-color: #f9f9f9;
border-radius: 4px;
transition: all 0.3s;
}
.condition-row:hover {
background-color: #f0f7ff;
}
.invalid-condition {
border: 1px dashed #f56c6c;
}
.condition-index {
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
background-color: #409eff;
color: white;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.field-select {
width: 150px;
margin-right: 10px;
}
.operator-select {
width: 120px;
margin-right: 10px;
}
.value-input {
width: 200px;
margin-right: 10px;
}
.between-inputs {
display: flex;
align-items: center;
width: 200px;
margin-right: 10px;
}
.value-placeholder {
width: 200px;
margin-right: 10px;
}
.field-type-hint {
color: #909399;
margin-left: 5px;
font-size: 12px;
}
.nested-group {
margin: 10px 0;
padding: 10px 0 10px 20px;
border-left: 2px solid #409eff;
background-color: #f9fafc;
border-radius: 0 4px 4px 0;
}
.nested-group-header {
margin-bottom: 10px;
}
.nested-group-title {
font-weight: bold;
color: #409eff;
}
.condition-actions {
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #ebeef5;
}
.remove-btn {
margin-left: auto;
}
.remove-group-btn {
margin-left: 10px;
}
.sql-preview {
margin-top: 20px;
padding: 15px;
background-color: #f8f8f8;
border-radius: 4px;
border-left: 3px solid #409eff;
}
.sql-preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.sql-preview-title {
font-size: 14px;
font-weight: bold;
color: #303133;
}
.sql-preview-content {
font-family: "Courier New", Courier, monospace;
background-color: #f8f8f8;
}
.empty-condition-hint {
padding: 15px;
text-align: center;
color: #909399;
background-color: #f5f7fa;
border-radius: 4px;
margin: 10px 0;
}
</style>
@@ -429,6 +429,7 @@
Vue.component("svg-icon", httpVueLoader("/components/plugins/sysSvgIcon/index.vue?v=" + new Date().getTime()))
Vue.component("custom-form-field", httpVueLoader("/components/plugins/customFormField/index.vue?v=" + new Date().getTime()))
Vue.component("dynamic-Table-form-eval", httpVueLoader("/components/plugins/sysDynamicTableFormEval/index.vue?v=" + new Date().getTime()))
Vue.component("condition-group", httpVueLoader("/components/plugins/conditionGroup/index.vue?v=" + new Date().getTime()))
</script>
</head>
<body>
@@ -3,12 +3,23 @@ layout("/layouts/platform.html"){
#-->
<style>
.pullTimeRadioGroup .el-radio {
.pullTimeRadioGroup .el-checkbox {
width: 100%;
margin-bottom: 10px;
margin: 0 0 10px 0;
}
.pullTimeRadioGroup .el-radio.is-bordered + .el-radio.is-bordered {
margin-left: 0;
.pullTimeRadioGroup .el-checkbox.is-bordered {
margin-left: 0 !important;
display: flex;
align-items: center;
}
.pullTimeRadioGroup .el-checkbox__input {
flex-shrink: 0;
}
.pullTimeRadioGroup .el-checkbox__label {
flex: 1;
}
</style>
@@ -16,7 +27,7 @@ layout("/layouts/platform.html"){
<el-card shadow="never">
<search @search="doSearch">
<search-item label="拉取时间">
<el-select clearable v-model="pageForm.pullTime" placeholder="请选择拉取时间">
<el-select clearable v-model="pageForm.pullTime" placeholder="请选择拉取时间" :clearable="false" @change="doSearch">
<el-option v-for="item in pullTimeOptions" :label="item.pullTime" :value="item.pullTime"></el-option>
</el-select>
</search-item>
@@ -55,15 +66,18 @@ layout("/layouts/platform.html"){
<el-button type="danger" size="mini" @click="openDelete" icon="el-icon-delete">删除本地数据源</el-button>
</table-tool>
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center" v-loading="tableLoading">
<el-table-column type="index" width="70" label="序号" fixed="left"></el-table-column>
<el-table-column type="index" width="70" label="序号" fixed="left" :index="indexMethod"></el-table-column>
<el-table-column prop="pullTime" label="拉取时间" width="170" fixed="left"></el-table-column>
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="sex" label="性别" sortable></el-table-column>
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="birthday" label="生日" sortable width="120"></el-table-column>
<!-- <el-table-column prop="mobile" label="手机号" width="120"></el-table-column>-->
<el-table-column prop="birthday" label="生日" sortable width="120">
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
</el-table-column>
<el-table-column prop="userState" label="在职状态" sortable width="120"></el-table-column>
<el-table-column prop="preparedBy" label="用人方式" sortable width="120"></el-table-column>
<el-table-column prop="preparedBy" label="人事编制" sortable width="120"></el-table-column>
<el-table-column prop="postDoctoralJoinDate" label="进站时间" sortable width="120"></el-table-column>
<el-table-column prop="personType" label="教职工类别" sortable width="120"></el-table-column>
<el-table-column prop="comeSchoolDate" label="来校年月" sortable width="120"></el-table-column>
<el-table-column prop="technicalTitle" label="技术职称" sortable width="120"></el-table-column>
@@ -79,14 +93,14 @@ layout("/layouts/platform.html"){
</el-card>
<el-dialog title="选择数据源" :visible.sync="pullTimeDialogVisible" width="30%">
<el-radio-group v-model="sourceTime" style="width: 100%" class="pullTimeRadioGroup">
<el-radio :label="item.pullTime" border v-for="item in pullTimeOptions" :key="item.pullTime">
<span>
<el-checkbox-group v-model="sourceTime" style="width: 100%" class="pullTimeRadioGroup">
<el-checkbox :label="item.pullTime" border v-for="item in pullTimeOptions" :key="item.pullTime">
<div style="display: flex; justify-content: space-between">
{{item.pullTime}}
<span style="float: right; color: red">rows:{{item.num}}</span>
</span>
</el-radio>
</el-radio-group>
<span style="color: red">rows:{{item.num}}</span>
</div>
</el-checkbox>
</el-checkbox-group>
<span slot="footer" class="dialog-footer">
<el-button @click="pullTimeDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doDeleteUser">确 定</el-button>
@@ -105,7 +119,7 @@ layout("/layouts/platform.html"){
preparedByOptions: [],
personTypeOptions: [],
pullTimeOptions: false,
sourceTime: null,
sourceTime: [],
pullTimeDialogVisible: false,
pullLoading: false
}
@@ -124,6 +138,7 @@ layout("/layouts/platform.html"){
.then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.getPullTimeOptions()
this.doSearch()
}
})
@@ -148,6 +163,13 @@ layout("/layouts/platform.html"){
this.$axios.post("/platform/sys/data/user/pull/pullTimeOptions").then((resp) => {
if (resp.code === 0) {
this.pullTimeOptions = resp.data
if (this.pullTimeOptions.length > 0) {
this.pageForm.pullTime = this.pullTimeOptions[0].pullTime
this.pageData()
} else {
this.tableData = []
this.pageForm.totalCount = 0
}
}
})
},
@@ -165,7 +187,7 @@ layout("/layouts/platform.html"){
}).then(() => {
this.$axios
.post("/platform/sys/data/user/pull/deleteByPullTime", {
pullTime: this.sourceTime
pullTime: JSON.stringify(this.sourceTime)
})
.then((resp) => {
if (resp.code === 0) {
@@ -178,7 +200,7 @@ layout("/layouts/platform.html"){
}
},
created() {
this.pageData()
// this.pageData()
this.getSearchOptions()
this.getPullTimeOptions()
}
@@ -18,26 +18,6 @@ layout("/layouts/platform.html"){
padding: 10px;
margin-bottom: 10px;
}
.condition-group {
border-left: 2px solid #409eff;
padding-left: 10px;
margin-bottom: 10px;
}
.condition-row {
margin-bottom: 10px;
display: flex;
align-items: center;
}
.condition-row .el-select {
margin-right: 10px;
}
.condition-actions {
margin-top: 10px;
}
</style>
<div id="app" v-cloak>
@@ -60,10 +40,10 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.userState" code="USER_STATE" style="width: 100%"></dict-select>
</search-item>
<search-item label="人事编制">
<dict-select v-model="pageForm.preparedBy" code="PREPARED_BY" style="width: 100%"></dict-select>
<dict-select v-model="pageForm.preparedBy" code="USER_PREPARED_BY_TYPE" style="width: 100%"></dict-select>
</search-item>
<search-item label="人员类型">
<dict-select v-model="pageForm.personType" code="PERSON_TYPE" style="width: 100%"></dict-select>
<dict-select v-model="pageForm.personType" code="USER_PERSON_TYPE" style="width: 100%"></dict-select>
</search-item>
</search>
</el-card>
@@ -85,8 +65,10 @@ layout("/layouts/platform.html"){
</el-table-column>
<el-table-column prop="changeTime" label="变更时间" sortable width="150"></el-table-column>
<el-table-column prop="sex" label="性别" sortable></el-table-column>
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="birthday" label="生日" sortable width="120"></el-table-column>
<!-- <el-table-column prop="mobile" label="手机号" width="120"></el-table-column>-->
<el-table-column prop="birthday" label="生日" sortable width="120">
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
</el-table-column>
<el-table-column prop="userState" label="在职状态" sortable width="120"></el-table-column>
<el-table-column prop="preparedBy" label="人事编制" sortable width="120"></el-table-column>
<el-table-column prop="personType" label="人员类型" sortable width="120"></el-table-column>
@@ -118,7 +100,7 @@ layout("/layouts/platform.html"){
</el-timeline-item>
<el-timeline-item timestamp="更新方式" placement="top">
<el-radio-group class="checkGroup" style="width: 100%" v-model="updateFromData.updateMode">
<el-radio-group class="checkGroup" style="width: 100%" v-model="updateFromData.updateMode" size="small">
<el-row>
<el-radio border label="ALL">全部更新</el-radio>
<el-radio border label="INCR">仅更新新增人员</el-radio>
@@ -131,12 +113,7 @@ layout("/layouts/platform.html"){
<div v-if="enableAdvancedConditions" class="condition-builder">
<!-- 条件构建器组件 -->
<condition-group
:group="updateFromData.conditionGroup"
:field-options="fieldOptions"
:operator-options="operatorOptions"
@remove="removeRootGroup"
></condition-group>
<condition-group :group="updateFromData.conditionGroup" :field_options="fieldOptions" @remove="removeRootGroup"></condition-group>
</div>
</el-timeline-item>
</el-timeline>
@@ -147,110 +124,7 @@ layout("/layouts/platform.html"){
</el-dialog>
</div>
<!-- 条件组组件模板 -->
<script type="text/x-template" id="condition-group-template">
<div class="condition-group">
<div class="condition-row">
<el-select v-model="group.logic" size="small" style="width: 80px">
<el-option label="AND" value="AND"></el-option>
<el-option label="OR" value="OR"></el-option>
</el-select>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="$emit('remove')"
v-if="canRemove"></el-button>
</div>
<!-- 条件列表 -->
<div v-for="(condition, index) in group.conditions" :key="'c-'+index" class="condition-row">
<el-select v-model="condition.field" placeholder="字段" size="small" style="width: 120px">
<el-option v-for="field in fieldOptions" :key="field.value" :label="field.label"
:value="field.value"></el-option>
</el-select>
<el-select v-model="condition.operator" placeholder="操作符" size="small" style="width: 100px">
<el-option v-for="op in operatorOptions" :key="op.value" :label="op.label"
:value="op.value"></el-option>
</el-select>
<el-input v-if="!isNullOperator(condition.operator)" v-model="condition.value" placeholder="值" size="small"
style="width: 150px"></el-input>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeCondition(index)"></el-button>
</div>
<!-- 嵌套条件组 -->
<div v-for="(nestedGroup, index) in group.groups" :key="'g-'+index">
<condition-group
:group="nestedGroup"
:field-options="fieldOptions"
:operator-options="operatorOptions"
:can-remove="true"
@remove="removeGroup(index)">
</condition-group>
</div>
<!-- 操作按钮 -->
<div class="condition-actions">
<el-button type="primary" size="mini" @click="addCondition">添加条件</el-button>
<el-button type="success" size="mini" @click="addGroup">添加条件组</el-button>
</div>
</div>
</script>
<script>
// 条件组组件
Vue.component("condition-group", {
template: "#condition-group-template",
props: {
group: {
type: Object,
required: true
},
fieldOptions: {
type: Array,
required: true
},
operatorOptions: {
type: Array,
required: true
},
canRemove: {
type: Boolean,
default: false
}
},
methods: {
addCondition() {
if (!this.group.conditions) {
this.$set(this.group, "conditions", [])
}
this.group.conditions.push({
field: "",
operator: "=",
value: ""
})
},
removeCondition(index) {
this.group.conditions.splice(index, 1)
},
addGroup() {
if (!this.group.groups) {
this.$set(this.group, "groups", [])
}
this.group.groups.push({
logic: "AND",
conditions: [],
groups: []
})
},
removeGroup(index) {
this.group.groups.splice(index, 1)
},
isNullOperator(operator) {
return operator === "IS NULL" || operator === "IS NOT NULL"
}
}
})
new Vue({
el: "#app",
dicts: ["MEMBER_CHANGE_TYPE"],
@@ -281,24 +155,13 @@ layout("/layouts/platform.html"){
{ label: "手机号", value: "mobile" },
{ label: "在职状态", value: "userState" },
{ label: "人事编制", value: "preparedBy" },
{ label: "进站时间", value: "postDoctoralJoinDate" },
{ label: "人员类型", value: "personType" },
{ label: "来校年月", value: "arrivalAtSchoolDate" },
{ label: "单位", value: "unitName" },
{ label: "单位编码", value: "unitId" },
{ label: "学历", value: "education" },
{ label: "学位", value: "academicDegree" }
],
// 操作符列表
operatorOptions: [
{ label: "等于", value: "=" },
{ label: "不等于", value: "!=" },
{ label: "大于", value: ">" },
{ label: "小于", value: "<" },
{ label: "大于等于", value: ">=" },
{ label: "小于等于", value: "<=" },
{ label: "包含", value: "LIKE" },
{ label: "为空", value: "IS NULL" },
{ label: "不为空", value: "IS NOT NULL" }
]
}
},
@@ -39,14 +39,7 @@ layout("/layouts/platform.html"){
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 :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:key="column.prop"
@@ -54,31 +47,24 @@ layout("/layouts/platform.html"){
: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=='provideTimeStart'">
<i class="el-icon-time"></i>
&ensp;{{row.provideTimeStart}}
<span v-if="row.provideTimeEnd">- {{row.provideTimeEnd}}</span>
</template>
<template scope="{row}" v-if="column.prop=='gift'">
<span v-if="row.flexible">福利套餐</span>
<span v-else>{{row.gift}}</span>
</template>
<!-- <template scope="{row}" v-if="column.prop=='gift'">-->
<!-- <span v-if="row.flexible">福利套餐</span>-->
<!-- <span v-else>{{row.gift}}</span>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="是否发布">
<template scope="{row}">
<span class="text-success" v-if="!row.isDisabled"></span>
<span class="text-danger" v-else></span>
</template>
</el-table-column>
<!-- <el-table-column label="是否发布">-->
<!-- <template scope="{row}">-->
<!-- <span class="text-success" v-if="!row.isDisabled">是</span>-->
<!-- <span class="text-danger" v-else>否</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column align="center" header-align="center" label="操作" prop="userOnline" width="150px">
<el-table-column label="操作" width="150px">
<template scope="{row}">
<el-dropdown @command="dropdownCommand">
<el-button :loading="submitLoading" plain size="mini">
@@ -86,15 +72,10 @@ layout("/layouts/platform.html"){
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'status',data:row}">{{row.isDisabled?'发布':'关闭'}}</el-dropdown-item>
<el-dropdown-item :command="{type:'sendMsg',data:row}">通知未选择人员</el-dropdown-item>
<!-- <el-dropdown-item :command="{type:'createList2',data:row}" v-if="row.created">更新福利名单</el-dropdown-item>-->
<el-dropdown-item :command="{type:'createList',data:row}">
<!-- {{row.created?'重置福利名单':'生成福利名单'}}-->
生成福利名单
</el-dropdown-item>
<!-- <el-dropdown-item :command="{type:'status',data:row}">{{row.isDisabled?'发布':'关闭'}}</el-dropdown-item>-->
<!-- <el-dropdown-item :command="{type:'sendMsg',data:row}">通知未选择人员</el-dropdown-item>-->
<el-dropdown-item :command="{type:'createList',data:row}">生成福利名单</el-dropdown-item>
<el-dropdown-item :command="{type:'edit',data:row}">编辑</el-dropdown-item>
<el-dropdown-item :command="{type:'delete',data:row}">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@@ -279,8 +260,11 @@ layout("/layouts/platform.html"){
tableColumns: [
{ prop: "year", label: "年度" },
{ prop: "name", label: "项目名称" },
{ prop: "gift", label: "福利礼品" },
{ prop: "provideTimeStart", label: "发放时间" }
{ prop: "choiceTimeStart", label: "开始选择时间" },
{ prop: "choiceTimeEnd", label: "结束选择时间" }
// { prop: "gift", label: "福利礼品" },
// { prop: "provideTimeStart", label: "发放时间" }
],
formRules: {
name: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
@@ -294,25 +278,18 @@ layout("/layouts/platform.html"){
gift: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
multiSelectNum: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
},
welfare_id: null,
welfarePersonTypeList: []
}
},
methods: {
dropdownCommand(command) {
const { type, data } = command
this.welfare_id = data.id
if (type === "view") {
this.openView(data.id)
} else if (type === "edit") {
if (type === "edit") {
this.openEdit(data)
} else if (type === "delete") {
this.doDelete(data.id)
} else if (type === "createList") {
//this.createList(data, false)
this.$refs.filterUserRef.onOpen(data.id)
} else if (type === "createList2") {
this.createList(data, true)
} else if (type === "status") {
this.projectStatusChange(data)
} else if (type === "sendMsg") {
@@ -414,9 +391,7 @@ layout("/layouts/platform.html"){
this.$message.warning(resp.msg)
}
},
openView() {
this.$refs.guava.view()
},
async openEdit(row) {
this.submitLoading = true
const resp = await this.$axios.post(loc() + "/findOne", { id: row.id })
@@ -425,36 +400,8 @@ layout("/layouts/platform.html"){
const data = resp.data
data.provideTime = [data.provideTimeStart, data.provideTimeEnd]
data.choiceTime = [data.choiceTimeStart, data.choiceTimeEnd]
// if (data.welfareProjectSubjects.length === 0) {
// data.welfareProjectSubjects = [
// {
// subjectName: "请输入福利信息",
// subjectType: data.isCheckBox,
// defaultOption: null,
// options: [
// {
// optionType: "套餐",
// optionName: "福利1",
// optionNameId: "",
// optionSort: "1",
// imgUrl: ""
// }
// ]
// }
// ]
// } else {
// data.welfareProjectSubjects.forEach((v) => {
// v.options.map((o) => {
// if (!o.optionNameId) {
// o.optionNameId = ""
// }
// })
// })
// }
this.formData = data
this.$refs.guava.edit()
} else {
this.notifyWarning(resp.msg)
}
},
doDelete(id) {
@@ -473,35 +420,6 @@ layout("/layouts/platform.html"){
}
this.submitLoading = false
})
},
async createList(row, flag) {
let msg
if (flag) {
msg = "系统根据现有的福利会员,更新当前福利名单,对已经选择的福利没有影响,请确认是否更新?"
} else {
msg = row.created
? "务必确认是否重新生成福利名单,如果确认,系统将清空已经选取的福利信息。请再次确认 !!"
: "确定要生成福利名单吗?"
}
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
//确认后再执行
this.submitLoading = true
const resp = await this.$axios.post(loc() + "/createList", {
id: row.id,
created: false
})
this.submitLoading = false
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.notifyWarning(resp.msg)
}
})
}
},
async created() {
@@ -99,7 +99,11 @@ layout("/layouts/platform.html"){
show-overflow-tooltip
v-for="column in tableColumns"
></el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作" width="100px"></el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作" width="100px">
<template slot-scope="{row}">
<el-button @click="handleSelect(row)" size="mini" type="primary">代选</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
@@ -170,7 +174,10 @@ layout("/layouts/platform.html"){
exportXlsx() {
this.$downLoad("/platform/welfare/selection/situation/exportXlsx", { pageForm: JSON.stringify(this.pageForm) })
}
},
// 管理员待选
handleSelect() {}
},
async created() {
this.getWelfareList()
@@ -337,6 +337,27 @@ layout("/layouts/platform_h5.html"){
text-align: center;
}
/* 调整确认弹窗布局,使按钮固定在底部 */
.confirm-content-scroll {
max-height: calc(70vh - 140px);
overflow-y: auto;
padding-bottom: 16px;
-webkit-overflow-scrolling: touch; /* 提升iOS滚动体验 */
}
.confirm-fixed-buttons {
position: sticky;
bottom: 0;
left: 0;
right: 0;
background: #fff;
padding-top: 12px;
z-index: 10;
border-top: 1px solid rgba(0, 0, 0, 0.05);
display: flex;
column-gap: 10px;
}
/* 手机号输入样式 */
.mobile-input-section {
margin-bottom: 20px;
@@ -441,42 +462,12 @@ layout("/layouts/platform_h5.html"){
font-size: 15px;
}
/* 提示信息样式 */
.confirm-notice-item {
display: flex;
align-items: flex-start;
padding: 12px;
background: #fff;
border-radius: 8px;
margin-bottom: 8px;
color: var(--primary-color);
font-size: 14px;
line-height: 1.5;
}
.confirm-notice-item:last-child {
margin-bottom: 0;
}
.confirm-notice-item.deadline {
color: var(--text-secondary);
}
.confirm-notice-item .van-icon {
font-size: 16px;
margin-right: 8px;
position: relative;
top: 2px;
flex-shrink: 0;
}
.action-sheet-buttons {
margin-top: 8px;
}
.action-sheet-cancel {
width: 100%;
margin-top: 12px;
}
.section-divider {
@@ -524,6 +515,22 @@ layout("/layouts/platform_h5.html"){
margin-left: 8px;
font-weight: normal;
}
/* 签名组件样式 */
.h5-signature {
margin-top: 8px;
border: 1px dashed var(--border-color);
border-radius: 8px;
background-color: #fff;
min-height: 150px;
}
.signature-tips {
color: var(--text-light);
font-size: 13px;
text-align: center;
margin-top: 6px;
}
</style>
<div id="app" v-cloak>
@@ -620,9 +627,9 @@ layout("/layouts/platform_h5.html"){
<!-- 单选模式使用单选按钮 -->
<div class="welfare-option-radio" v-if="projectInfo.isCheckBox === 'radio'">
<van-radio
:name="option.id"
v-model="selectedRadioId"
<van-radio
:name="option.id"
v-model="selectedRadioId"
@click.stop="isDeadlinePassed ? $toast.fail('已过选择截止时间,无法修改') : selectRadioOption(option.id)"
:disabled="isDeadlinePassed"
></van-radio>
@@ -649,72 +656,72 @@ layout("/layouts/platform_h5.html"){
<!-- 底部提交按钮 -->
<div class="welfare-footer" v-if="projectInfo.id">
<van-button
type="primary"
class="welfare-submit-btn"
:disabled="submitButtonDisabled"
@click="submitSelection"
round
>{{ isDeadlinePassed ? '已截止' : '确认选择' }}</van-button>
<van-button type="primary" class="welfare-submit-btn" :disabled="submitButtonDisabled" @click="submitSelection" round>
{{ isDeadlinePassed ? '已截止' : '确认选择' }}
</van-button>
</div>
<!-- 确认弹窗 -->
<van-action-sheet v-model="showConfirmDialog" :close-on-click-overlay="false">
<van-action-sheet v-model="showConfirmDialog" :close-on-click-overlay="false" :round="true" :style="{ maxHeight: '90%' }">
<div class="confirm-action-sheet">
<div class="confirm-sheet-title">确认选择</div>
<!-- 手机号输入 -->
<div class="mobile-input-section">
<van-field
v-model="userMobile"
label="联系电话"
placeholder="请输入手机号码"
:error="mobileError"
@focus="mobileError = false"
maxlength="11"
required
></van-field>
</div>
<div class="confirm-content-scroll">
<!-- 手机号输入 -->
<div class="mobile-input-section">
<van-field
v-model="formData.mobile"
label="联系电话"
placeholder="请输入手机号码"
:error="mobileError"
@focus="mobileError = false"
maxlength="11"
required
></van-field>
<!--
收货地址字段预留位置
<van-field
v-if="projectInfo.needAddress"
v-model="formData.address"
label="收货地址"
placeholder="请输入收货地址"
type="textarea"
rows="2"
required
></van-field>
-->
</div>
<!-- 选择内容 -->
<div class="confirm-section">
<div class="confirm-section-title">已选择项目</div>
<div class="selected-items">
<div v-for="option in selectedOptions" :key="option.id" class="selected-item">
<span class="selected-item-name">{{ option.optionName }}</span>
<span class="selected-item-count" v-if="projectInfo.isCheckBox === 'checkBox'">× {{ option.selectNum }}</span>
<!-- 选择内容 -->
<div class="confirm-section">
<div class="confirm-section-title">已选择项目</div>
<div class="selected-items">
<div v-for="option in selectedOptions" :key="option.id" class="selected-item">
<span class="selected-item-name">{{ option.optionName }}</span>
<span class="selected-item-count" v-if="projectInfo.isCheckBox === 'checkBox'">× {{ option.selectNum }}</span>
</div>
</div>
<div class="confirm-dialog-total" v-if="projectInfo.isCheckBox === 'checkBox'">
<span class="total-label">总数量</span>
<span class="total-value">{{ totalSelectedCount }} 份</span>
</div>
</div>
<div class="confirm-dialog-total" v-if="projectInfo.isCheckBox === 'checkBox'">
<span class="total-label">总数量</span>
<span class="total-value">{{ totalSelectedCount }} 份</span>
<!-- 签字组件 -->
<div class="confirm-section" v-if="projectInfo.signMode === 2">
<div class="confirm-section-title">请签字确认</div>
<h5-signature v-model="formData.userSign" ref="signatureRef"></h5-signature>
<div class="signature-tips">{{ formData.userSign ? '您已完成签名' : '请在上方空白区域完成签名' }}</div>
<div style="text-align: right; margin-top: 8px">
<van-button size="small" type="default" @click="resetSignature">重新签名</van-button>
</div>
</div>
</div>
<!-- 提示信息 -->
<div class="confirm-section" v-if="deadlineText || hasSubmittedBefore || isDeadlinePassed">
<div class="confirm-section-title">注意事项</div>
<div class="confirm-notice-item" v-if="hasSubmittedBefore">
<van-icon name="info-o" />
<span>{{ confirmMessage }}</span>
</div>
<div class="confirm-notice-item deadline" v-if="deadlineText && !isDeadlinePassed">
<van-icon name="clock-o" />
<span>{{ deadlineText }}</span>
</div>
<div class="confirm-notice-item" style="color: var(--danger-color)" v-if="isDeadlinePassed">
<van-icon name="warning-o" />
<span>选择截止时间已过,无法修改</span>
</div>
</div>
<div class="action-sheet-buttons">
<van-button type="primary" block round @click="doSubmit">{{ hasSubmittedBefore ? '确认修改' : '确认提交' }}</van-button>
<div class="confirm-fixed-buttons">
<van-button type="default" block round class="action-sheet-cancel" @click="showConfirmDialog = false">取消</van-button>
<van-button type="primary" block round @click="doSubmit">{{ hasSubmittedBefore ? '确认修改' : '确认提交' }}</van-button>
</div>
</div>
</van-action-sheet>
@@ -744,11 +751,14 @@ layout("/layouts/platform_h5.html"){
showConfirmDialog: false,
isSubmitting: false,
hasSubmittedBefore: false, // 是否之前提交过
deadlineTime: null, // 选择截止时间
showOptionDetailDialog: false, // 选项详情弹窗
selectedOption: null, // 当前选中的选项
userMobile: "", // 用户手机号
mobileError: false // 手机号错误标记
mobileError: false, // 手机号错误标记
formData: {
userSign: "", // 用户签名
mobile: "", // 手机号码
address: "" // 收货地址(预留)
}
}
},
@@ -796,32 +806,6 @@ layout("/layouts/platform_h5.html"){
const diffHours = (endTime - now) / (1000 * 60 * 60)
return diffHours > 0 && diffHours < 24
},
deadlineText() {
if (!this.deadlineTime) return ""
const now = new Date()
const deadline = new Date(this.deadlineTime)
const diffHours = Math.floor((deadline - now) / (1000 * 60 * 60))
const diffMinutes = Math.floor((deadline - now) / (1000 * 60)) % 60
if (diffHours > 24) {
const diffDays = Math.floor(diffHours / 24)
return "还剩 " + diffDays + " 天可以修改"
} else if (diffHours > 0) {
return "还剩 " + diffHours + " 小时 " + diffMinutes + " 分钟可以修改"
} else if (diffMinutes > 0) {
return "还剩 " + diffMinutes + " 分钟可以修改"
} else {
return "选择时间已截止"
}
},
confirmMessage() {
if (this.hasSubmittedBefore) {
return "修改后的选择将覆盖之前的选择"
}
return "请仔细确认您的选择"
}
},
@@ -830,7 +814,6 @@ layout("/layouts/platform_h5.html"){
this.$axios.post("/platform/welfare/project/mange/findOne", { id: this.projectId }).then((res) => {
if (res.code === 0) {
this.projectInfo = res.data
this.deadlineTime = this.projectInfo.choiceTimeEnd
// 初始化选项的selectNum为0
if (this.projectInfo.options) {
@@ -855,11 +838,17 @@ layout("/layouts/platform_h5.html"){
// 如果有用户选择数据,从中获取手机号
if (this.userSelection && this.userSelection.length > 0 && this.userSelection[0].mobile) {
this.userMobile = this.userSelection[0].mobile
this.formData.mobile = this.userSelection[0].mobile
// 获取签名信息(如果有)
if (this.userSelection[0].userSign) {
this.formData.userSign = this.userSelection[0].userSign
}
} else if (this.$store.user && this.$store.user.mobile) {
// 如果没有选择过,使用store中的默认手机号
debugger
this.userMobile = this.$store.user.mobile
this.formData.mobile = this.$store.user.mobile
}
// 设置已选择的选项
@@ -904,6 +893,12 @@ layout("/layouts/platform_h5.html"){
return
}
// 如果需要签字,验证签名
if (this.projectInfo.signMode === 2 && !this.formData.userSign) {
this.$toast.fail("请完成签名确认")
return
}
if (this.isSubmitting) return
this.isSubmitting = true
@@ -922,7 +917,7 @@ layout("/layouts/platform_h5.html"){
{
selectOptionId: this.selectedRadioId,
selectNum: 1,
mobile: this.userMobile
mobile: this.formData.mobile
}
]
}
@@ -932,10 +927,24 @@ layout("/layouts/platform_h5.html"){
selections = this.selectedOptions.map((option) => ({
selectOptionId: option.id,
selectNum: option.selectNum,
mobile: this.userMobile
mobile: this.formData.mobile
}))
}
// 如果需要签字,添加签名数据
if (this.projectInfo.signMode === 2) {
selections.forEach((selection) => {
selection.userSign = this.formData.userSign
})
}
// 未来可扩展添加收货地址
if (this.formData.address) {
selections.forEach((selection) => {
selection.address = this.formData.address
})
}
this.$axios
.post("/platform/welfare/userSelect/confirmSelect", {
projectId: this.projectId,
@@ -963,14 +972,14 @@ layout("/layouts/platform_h5.html"){
// 验证手机号
validateMobile() {
if (!this.userMobile) {
if (!this.formData.mobile) {
this.mobileError = true
this.$toast.fail("请输入手机号码")
return false
}
const mobileReg = /^1[3456789]\d{9}$/
if (!mobileReg.test(this.userMobile)) {
if (!mobileReg.test(this.formData.mobile)) {
this.mobileError = true
this.$toast.fail("请输入正确的手机号码")
return false
@@ -1022,6 +1031,14 @@ layout("/layouts/platform_h5.html"){
return
}
// 重置签名数据
if (this.projectInfo.signMode === 2) {
// 如果已经有签名数据,且签名模式是修改,保留原签名
if (!this.formData.userSign || !this.hasSubmittedBefore) {
this.formData.userSign = ""
}
}
this.showConfirmDialog = true
},
@@ -1056,6 +1073,15 @@ layout("/layouts/platform_h5.html"){
this.selectedOption = option
this.showOptionDetailDialog = true
},
// 重置签名
resetSignature() {
this.formData.userSign = ""
// 如果组件有reset方法,调用它
if (this.$refs.signatureRef && typeof this.$refs.signatureRef.reset === 'function') {
this.$refs.signatureRef.reset()
}
},
// 切换选项选中状态
toggleOption(option) {
@@ -1103,7 +1129,7 @@ layout("/layouts/platform_h5.html"){
deep: true,
handler(options) {
if (!options) return
if (this.isDeadlinePassed) return // 如果已过期,不处理数量变化
if (this.isDeadlinePassed) return // 如果已过期,不处理数量变化
const maxSelect = this.projectInfo.multiSelectNum || options.length
const totalCount = options.reduce((sum, option) => sum + (option.selectNum || 0), 0)
@@ -1118,6 +1144,21 @@ layout("/layouts/platform_h5.html"){
}
}
}
},
// 监听确认弹窗显示状态
showConfirmDialog(val) {
if (val && this.projectInfo.signMode === 2) {
// 在下一个渲染周期后更新签名组件
this.$nextTick(() => {
if (this.$refs.signatureRef) {
// 如果组件有setSignature或类似方法可以调用
if (this.formData.userSign && typeof this.$refs.signatureRef.setSignature === 'function') {
this.$refs.signatureRef.setSignature(this.formData.userSign)
}
}
})
}
}
},
@@ -78,8 +78,6 @@ layout("/layouts/platform_h5.html"){
您的福利选择已提交成功!
<br />
请在选择时间截止前,您仍可以重新选择并修改。
<br />
请留意系统通知,了解福利发放信息。
</div>
<div class="button-group">