feat(emoji): manage grouped access rules

This commit is contained in:
zhx 2026-07-23 19:21:40 +08:00
parent 942e678f1a
commit 3f7bf0d7f0
6 changed files with 159 additions and 16 deletions

View File

@ -5276,7 +5276,11 @@ export default {
},
table: {
salePrice: 'Sale Price',
shelfStatus: 'On/Off Shelf'
shelfStatus: 'On/Off Shelf',
vipRange: 'VIP Range',
wealthRange: 'Wealth Range',
charmRange: 'Charm Range',
manageResources: 'Emojis'
},
form: {
groupCode: 'Group Code',
@ -5284,7 +5288,12 @@ export default {
amount: 'Sale Price',
shelfStatus: 'On/Off Shelf',
ktvStatus: 'KTV Emoji',
weight: 'Weight'
weight: 'Weight',
accessRules: 'Access Rules',
vipRange: 'VIP Level Range',
wealthRange: 'Wealth Level Range',
charmRange: 'Charm Level Range',
rangeHelp: '0 means that boundary is unrestricted. Users must meet every configured level rule.'
},
placeholder: {
groupCode: 'Group Code',
@ -5321,14 +5330,16 @@ export default {
offShelf: 'Off Shelf',
yes: 'Yes',
no: 'No',
free: 'Free'
free: 'Free',
unrestricted: 'Unrestricted'
},
dialog: {
add: 'Add',
edit: 'Edit'
},
validation: {
required: 'This field is required'
required: 'This field is required',
invalidLevelRange: 'Invalid level range: max must be 0 or greater than or equal to min'
},
message: {
onShelfSuccess: 'Listed successfully',

View File

@ -5273,7 +5273,11 @@ export default {
},
table: {
salePrice: '售卖价格',
shelfStatus: '上/下架'
shelfStatus: '上/下架',
vipRange: 'VIP区间',
wealthRange: '财富区间',
charmRange: '魅力区间',
manageResources: '表情资源'
},
form: {
groupCode: '分组Code',
@ -5281,7 +5285,12 @@ export default {
amount: '售卖价格',
shelfStatus: '上/下架',
ktvStatus: 'KTV表情',
weight: '权重'
weight: '权重',
accessRules: '使用权限',
vipRange: 'VIP等级区间',
wealthRange: '财富等级区间',
charmRange: '魅力等级区间',
rangeHelp: '0表示该边界不限制配置多类等级时用户需要同时满足全部条件。'
},
placeholder: {
groupCode: '分组Code',
@ -5318,14 +5327,16 @@ export default {
offShelf: '下架',
yes: '是',
no: '否',
free: '免费'
free: '免费',
unrestricted: '不限'
},
dialog: {
add: '添加',
edit: '修改'
},
validation: {
required: '必填字段不可为空'
required: '必填字段不可为空',
invalidLevelRange: '等级区间无效最大值必须为0或不小于最小值'
},
message: {
onShelfSuccess: '上架成功',

View File

@ -317,6 +317,12 @@ function getFormData() {
export default {
name: 'EmojiConfig',
components: { Pagination },
props: {
initialGroup: {
type: Object,
default: null
}
},
data() {
const commonRules = [
{ required: true, message: this.$t('pages.emojiManagement.validation.required'), trigger: 'blur' }
@ -389,10 +395,16 @@ export default {
created() {
const that = this
const querySystem = this.permissionsSysOriginPlatforms[0]
if (!querySystem) {
const sysOrigin = this.initialGroup && this.initialGroup.sysOrigin
? this.initialGroup.sysOrigin
: querySystem && querySystem.value
if (!sysOrigin) {
return
}
that.listQuery.sysOrigin = querySystem.value
that.listQuery.sysOrigin = sysOrigin
that.listQuery.groupId = this.initialGroup && this.initialGroup.id
? this.initialGroup.id
: ''
that.renderData()
that.loadGroupList()
},

View File

@ -7,10 +7,10 @@
:append-to-body="true"
:before-close="handleClose"
:close-on-click-modal="false"
width="450px"
width="720px"
>
<div v-loading="submitLoading">
<el-form ref="form" :model="form" label-width="110px" :rules="formRules" style="margin-right: 20px;">
<el-form ref="form" :model="form" label-width="150px" :rules="formRules" style="margin-right: 20px;">
<el-form-item
v-if="!form.id"
:label="$t('pages.emojiManagement.common.system')"
@ -77,6 +77,29 @@
<el-input v-model.trim="form.sort" v-number :placeholder="$t('pages.emojiManagement.group.placeholder.weight')" />
</el-form-item>
<el-divider content-position="left">{{ $t('pages.emojiManagement.group.form.accessRules') }}</el-divider>
<el-form-item :label="$t('pages.emojiManagement.group.form.vipRange')">
<el-input-number v-model="form.minVipLevel" :min="0" :max="6" controls-position="right" />
<span class="range-separator">-</span>
<el-input-number v-model="form.maxVipLevel" :min="0" :max="6" controls-position="right" />
</el-form-item>
<el-form-item :label="$t('pages.emojiManagement.group.form.wealthRange')">
<el-input-number v-model="form.minWealthLevel" :min="0" :max="9999" controls-position="right" />
<span class="range-separator">-</span>
<el-input-number v-model="form.maxWealthLevel" :min="0" :max="9999" controls-position="right" />
</el-form-item>
<el-form-item :label="$t('pages.emojiManagement.group.form.charmRange')">
<el-input-number v-model="form.minCharmLevel" :min="0" :max="9999" controls-position="right" />
<span class="range-separator">-</span>
<el-input-number v-model="form.maxCharmLevel" :min="0" :max="9999" controls-position="right" />
</el-form-item>
<el-alert
:title="$t('pages.emojiManagement.group.form.rangeHelp')"
type="info"
:closable="false"
show-icon
/>
<el-form-item>
<el-button type="primary" @click="submitForm()">{{ $t('common.save') }}</el-button>
<el-button @click="handleClose()">{{ $t('common.cancel') }}</el-button>
@ -117,7 +140,13 @@ export default {
sysOrigin: '',
shelfStatus: '',
ktvStatus: '',
amount: ''
amount: '',
minVipLevel: 0,
maxVipLevel: 0,
minWealthLevel: 0,
maxWealthLevel: 0,
minCharmLevel: 0,
maxCharmLevel: 0
},
formRules: {
cover: commonRules,
@ -155,6 +184,17 @@ export default {
}
this.form = deepClone(newVal)
const accessLevelFields = [
'minVipLevel',
'maxVipLevel',
'minWealthLevel',
'maxWealthLevel',
'minCharmLevel',
'maxCharmLevel'
]
accessLevelFields.forEach(field => {
this.$set(this.form, field, Number(newVal[field] || 0))
})
if (this.form.cover) {
this.coverFileList = getElementUiUploadFile(this.form.cover)
}
@ -187,6 +227,11 @@ export default {
console.error('error submit!!')
return false
}
// 0 0 .
if (!that.validateAccessLevelRanges()) {
that.$message.error(that.$t('pages.emojiManagement.validation.invalidLevelRange'))
return false
}
that.submitLoading = true
addOrUpdateGroup(that.form).then(res => {
that.submitLoading = false
@ -198,10 +243,23 @@ export default {
})
return
})
},
validateAccessLevelRanges() {
return [
[this.form.minVipLevel, this.form.maxVipLevel],
[this.form.minWealthLevel, this.form.maxWealthLevel],
[this.form.minCharmLevel, this.form.maxCharmLevel]
].every(([minLevel, maxLevel]) => {
const min = Number(minLevel || 0)
const max = Number(maxLevel || 0)
return min >= 0 && max >= 0 && (max === 0 || min <= max)
})
}
}
}
</script>
<style scoped lang="scss">
.range-separator {
margin: 0 10px;
}
</style>

View File

@ -105,16 +105,32 @@
</div>
</template>
</el-table-column>
<el-table-column :label="$t('pages.emojiManagement.group.table.vipRange')" align="center" width="120">
<template slot-scope="scope">
{{ formatLevelRange(scope.row.minVipLevel, scope.row.maxVipLevel, 'VIP') }}
</template>
</el-table-column>
<el-table-column :label="$t('pages.emojiManagement.group.table.wealthRange')" align="center" width="120">
<template slot-scope="scope">
{{ formatLevelRange(scope.row.minWealthLevel, scope.row.maxWealthLevel) }}
</template>
</el-table-column>
<el-table-column :label="$t('pages.emojiManagement.group.table.charmRange')" align="center" width="120">
<template slot-scope="scope">
{{ formatLevelRange(scope.row.minCharmLevel, scope.row.maxCharmLevel) }}
</template>
</el-table-column>
<el-table-column :label="$t('pages.emojiManagement.common.sort')" prop="sort" align="center" />
<el-table-column :label="$t('pages.emojiManagement.common.createdAt')" prop="createTime" width="200" align="center">
<template slot-scope="scope">
{{ scope.row.createTime | dateFormat }}
</template>
</el-table-column>
<el-table-column :label="$t('pages.emojiManagement.common.actions')" fixed="right" align="center" width="100">
<el-table-column :label="$t('pages.emojiManagement.common.actions')" fixed="right" align="center" width="170">
<template slot-scope="scope">
<div>
<el-button type="text" @click.native="clickEdit(scope.row)">{{ $t('pages.emojiManagement.common.edit') }}</el-button>
<el-button type="text" @click.native="clickManageResources(scope.row)">{{ $t('pages.emojiManagement.group.table.manageResources') }}</el-button>
</div>
</template>
</el-table-column>
@ -210,6 +226,23 @@ export default {
this.thisClickRow = Object.assign({}, row)
this.formEditVisiable = true
},
clickManageResources(row) {
this.$emit('manage-resources', Object.assign({}, row))
},
formatLevelRange(minLevel, maxLevel, prefix = '') {
const min = Number(minLevel || 0)
const max = Number(maxLevel || 0)
const value = min === 0 && max === 0
? this.$t('pages.emojiManagement.options.unrestricted')
: max === 0
? `${min}+`
: min === 0
? `${max}`
: `${min}-${max}`
return prefix && value !== this.$t('pages.emojiManagement.options.unrestricted')
? `${prefix}${value}`
: value
},
formEditSuccess() {
this.handleSearch()
this.formEditVisiable = false

View File

@ -2,7 +2,11 @@
<div class="app-container">
<el-tabs v-model="activeName">
<el-tab-pane v-for="item in tables" :key="item.name" :label="$t(item.titleKey)" :name="item.component" />
<component :is="activeName" />
<component
:is="activeName"
v-bind="activeComponentProps"
@manage-resources="handleManageResources"
/>
</el-tabs>
</div>
</template>
@ -15,6 +19,7 @@ export default {
data() {
return {
activeName: 'EmojiGroup',
selectedGroup: null,
tables: [
{
titleKey: 'pages.emojiManagement.tabs.group',
@ -26,6 +31,19 @@ export default {
}
]
}
},
computed: {
activeComponentProps() {
return this.activeName === 'EmojiConf'
? { initialGroup: this.selectedGroup }
: {}
}
},
methods: {
handleManageResources(group) {
this.selectedGroup = group
this.activeName = 'EmojiConf'
}
}
}
</script>