提交 a96af5d6 作者: 毛细亚

合并分支 'release' 到 'master'

上线掌游 10.4 版本

查看合并请求 !34
......@@ -1424,3 +1424,46 @@ export function getClonePackageLink(data) {
})
})
}
// 使用权益
export function useBenefit(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/marketing_role_grade/useRight',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 使用权益记录
export function useRightList(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/marketing_role_grade/useRightList',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 发送邮件
export function sendEmail(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/operator_task/sendEmail',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
......@@ -8,22 +8,22 @@
>
<div>
<el-form ref="ruleForm" :model="ruleForm" label-width="100px" class="content">
<el-form-item label="选择角色">
<el-form-item label="选择角色:">
<el-select v-model="ruleForm.role_id" placeholder="请选择角色" style="width:90%;margin-bottom:10px;" @change="selectRole">
<el-option
v-for="(item,index) in roleList"
:key="index+1"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="活动类型">
<el-form-item label="活动类型:">
<el-select v-model="ruleForm.gift_type" placeholder="请选择" style="width:90%;margin-bottom:10px;" @change="giftTypeResult">
<el-option
v-for="(item,index) in giftTypeList"
:key="index+1"
:key="item.value"
:label="item.label"
:value="item.value"
>
......@@ -31,11 +31,11 @@
</el-select>
</el-form-item>
<!-- 活动类型为角色累充的时候 活动可以多选其他的都为单选 -->
<el-form-item label="选择活动" prop="rule_id">
<el-form-item label="选择活动:" prop="rule_id">
<el-select v-model="ruleForm.rule_id" :disabled="activeList.length==0" placeholder="请选择" style="width:90%;margin-bottom:10px;" :multiple="ruleForm.gift_type==1 || ruleForm.gift_type == 4 || ruleForm.gift_type== 5 " clearable @change="activeListResult">
<el-option
v-for="(item,index) in activeList"
:key="index+1"
:key="item.id"
:label="item.title_name"
:value="item.id"
>
......@@ -56,16 +56,16 @@
</el-form>
<!-- 申请礼包 -->
<!-- 角色累充 -->
<roleRecharge v-if="showGiftDetails && (ruleForm.gift_type==1 || ruleForm.gift_type==4 || ruleForm.gift_type==5) && roleActiveInfo.length>0" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="roleActiveInfo" :gift-info="giftDetailsInfo" title="礼包详情" />
<roleRecharge v-if="showGiftDetails && (ruleForm.gift_type==1 || ruleForm.gift_type==4 || ruleForm.gift_type==5) && roleActiveInfo.length>0" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="roleActiveInfo" :task_id="task_id" :gift-info="giftDetailsInfo" title="礼包详情" />
<!-- 时间段累充 和 单日累充 积分关的情况 -->
<roleTimeRecharge v-if="showGiftDetails && (ruleForm.gift_type==2 || (ruleForm.gift_type==3 && activeInfo.exchange_score_status==2 ) ) && activeInfo.id " :change-date="changeDate" :request-loading="requestLoading" :show.sync="showGiftDetails" :active-info="activeInfo" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
<!-- 单日累充 积分开的情况 -->
<oneDayCharge v-if="showGiftDetails && ruleForm.gift_type==3 && activeInfo.exchange_score_status==1 && activeInfo.id" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="activeInfo" :change-date="changeDate" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
<roleTimeRecharge v-if="showGiftDetails && (ruleForm.gift_type==2 || ruleForm.gift_type == 7 || (ruleForm.gift_type==3 && activeInfo.exchange_score_status==2 ) ) && activeInfo.id " :change-date="changeDate" :request-loading="requestLoading" :task_id="task_id" :show.sync="showGiftDetails" :active-info="activeInfo" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
<!-- 单日累充 积分开的情况 显示 svip 权益 并且可以选择 svip权益-->
<oneDayCharge v-if="showGiftDetails && (ruleForm.gift_type==3 || ruleForm.gift_type == 7) && activeInfo.exchange_score_status==1 && activeInfo.id" :show.sync="showGiftDetails" :task_id="task_id" :request-loading="requestLoading" :active-info="activeInfo" :change-date="changeDate" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsSVIPInfo="giftDetailsSVIPInfo" @giftDetailsInfo="requestDetailsInfo" />
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { roleList, activeList, giftBagApply, giftTypeList, giftDetailsData } from '@/api/game'
import { getRoleHoLo, activeList, giftBagApply, giftTypeList, giftDetailsData } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex'
// import giftDetails from './giftDetails.vue'
import roleRecharge from './giftDetails/roleRecharge.vue'
......@@ -79,8 +79,8 @@
oneDayCharge, // 单日累充
roleTimeRecharge // 角色时间段累充
},
// type 3:image 4:video
props: ['show', 'width', 'title'],
// type 3:image 4:video task_id // 账号任务点击礼包申请过来传递的任务id member_id // 我的任务 任务详情 点击 礼包申请的时候 需要用到任务详情的 member_id,这时候需要传递过来
props: ['show', 'width', 'title', 'task_id','member_id'],
data() {
return {
roleList: [],
......@@ -124,6 +124,15 @@
this.requestRoleList()
this.giftTypeListData()
},
beforeDestroy() {
// 清理组件销毁时的状态,防止内存泄漏
this.roleList = []
this.activeList = []
this.giftTypeList = []
this.roleActiveInfo = []
this.activeInfo = {}
this.giftDetailsInfo = {}
},
methods: {
requestActiveList() {
if (this.ruleForm.role_id !== '' && this.ruleForm.gift_type !== '') {
......@@ -156,15 +165,18 @@
})
},
requestRoleList() {
if (this.accountSelect == '') {
if (this.accountSelect == '' && !this.member_id) {
this.$message.warning('暂无关联的账号,请先去关联账号!')
return false
}
const data = {
api_search_name: '',
member_id: this.accountSelect
member_id:this.member_id || this.accountSelect, // 先取任务详情的member_id,没有的话取账号的member_id
search_type: 'list',
page_size:100,
page:1
}
roleList(data).then(res => {
getRoleHoLo(data).then(res => {
if (res.status_code == 1) {
if (res.data.data.length > 0) {
const list = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) })
......@@ -197,7 +209,7 @@
this.activeList = []
const gift_type = this.giftTypeList.find(item => item.value == data)
console.log(gift_type, 'gift_type')
this.gift_type_text = gift_type.label
this.gift_type_text = gift_type.label || ''
this.requestActiveList()
this.activeInfo = {}
this.giftInfo = {}
......@@ -246,7 +258,7 @@
this.showGiftDetails = true
} else {
this.ruleForm.recharge_date = ''
if (this.ruleForm.gift_type == 2) {
if (this.ruleForm.gift_type == 2 || this.ruleForm.gift_type == 7) {
this.requestGiftDetails()
this.showGiftDetails = true
}
......@@ -274,6 +286,21 @@
this.$message.warning('请选择充值日期')
}
},
// 积分开的情况 显示 svip 权益 并且可以选择 svip权益
giftDetailsSVIPInfo(params){
console.log(params, 'params')
const data = {
role_id: this.ruleForm.role_id,
rule_id: this.ruleForm.rule_id.toString(),
recharge_date: params.recharge_date || '',
right_type: params.right_type || '',
select_type: params.select_type || ''
}
giftDetailsData(data).then(res => {
this.giftDetailsInfo = res.data
this.showGiftDetails = true
})
},
requestGiftDetails(value) {
const data = {
role_id: this.ruleForm.role_id,
......
......@@ -55,7 +55,7 @@
</div>
</div>
<!-- 活动列表 -->
<span class="dialog-footer rowFlex">
<span class="rowFlex">
<el-button class="btn" type="primary" :loading="loading" @click="submit">确 定</el-button>
<el-button class="btn" @click="close">取 消</el-button>
</span>
......@@ -68,7 +68,7 @@
export default {
name: 'confirmLayer',
// type 3:image 4:video
props: ['show', 'width', 'title', 'activeInfo', 'remark'],
props: ['show', 'width', 'title', 'activeInfo', 'remark','task_id','svipObj'],
data() {
return {
loading: false
......@@ -104,8 +104,11 @@
role_id,
remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '',
task_id: this.task_id || null,
create_user: this.cser_name,
rule: rule
rule: rule,
right_type: this.svipObj?.right_type || '',
select_type: this.svipObj?.select_type || ''
}
giftBagApply(data).then(res => {
this.loading = false
......
......@@ -28,6 +28,13 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item label="svip权益">
<el-select v-model.trim="form.right_type" filterable style="width:100%;"
placeholder="请选择svip权益" @change="searchInput">
<el-option v-for="item in benefitOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="角色名称">
<el-input v-model="form.role_name_or_cp_id" placeholder="请输入角色名称" style="width:100%;"
@change="searchInput"></el-input>
......@@ -59,6 +66,7 @@
</div>
<el-collapse-transition>
<div v-if="item.showDetails">
<p class="text hidden"><label>svip权益:</label> {{ item.right_type_name || '-'}}</p>
<p v-if="item.status == '待提交'" class="text"><label>状态:</label> <span class="noSend">{{ item.status
}}</span> </p>
<p v-else-if="item.status == '已提交'" class="text"><label>状态:</label> <span class="sended">{{
......@@ -165,8 +173,10 @@ export default {
role_name_or_cp_id: '',
member_id: '',
active_title: '',
gift_type: ''
gift_type: '',
right_type: '',
},
benefitOptions: [],
inputValue: '',
pageInfo: {
page: 0,
......@@ -198,6 +208,7 @@ export default {
mounted() {
this.requestGameList()
this.requestGiftType()
this.getBenefitOptions()
},
methods: {
// 重新拉去数据
......@@ -286,6 +297,27 @@ export default {
this.emailGiftList = []
this.requestemailGiftList()
},
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
const showList = ['转生石福利','月核心玩家礼包','超R生日福利礼包','超R行会专属礼包']
this.benefitOptions = res.data.data.filter((item, index) => {
return showList.includes(item.label)
}).map(item => ({
...item,
value: item.value || item.id // 确保每个选项都有value属性,优先使用value,不存在则使用id
}));
console.log(this.benefitOptions)
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
requestemailGiftList() {
this.listLoading = true
if (this.accountSelect == '') {
......
......@@ -24,9 +24,23 @@
<div class="activeValue">{{ activeInfo.recharge_start_date + '至' + activeInfo.recharge_end_date }}</div>
</div>
<!-- 选择的时候重新请求活动详情接口 -->
<div class="activeItem rowFlex">
<div class="activeLabel">充值日期</div>
<div style="display: flex; align-items: center;width: 100%;">
<el-select v-model="select_type" :clearable="false" style="width: 120px" @change="onSelectTypeChange">
<el-option label="充值日期" :value="1"></el-option>
<el-option label="SVIP权益" :value="2"></el-option>
</el-select>
<template v-if="select_type === 1">
<el-date-picker v-model="recharge_date_time" :default-value="activeInfo.recharge_date" style="width: 210px" type="date" value-format="yyyy-MM-dd" :picker-options="activeInfo.pickerOptions " @change="dateChange"> </el-date-picker>
</template>
<template v-else-if="select_type === 2">
<el-select v-model="right_type" :clearable="false" style="width: 210px" placeholder="请选择权益" @change="onRightTypeChange">
<el-option v-for="item in benefitOptions" :key="item.id || item.value" :label="item.label" :value="item.value || item.id"></el-option>
</el-select>
</template>
</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">申请角色</div>
......@@ -127,13 +141,13 @@
<el-button class="btn" size="small" @click="close">取 消</el-button>
</span>
<!-- 确认弹窗 -->
<confirmLayer v-if="showConfirmLayer" :remark="remark" :active-info="[activeInfo]" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
<confirmLayer v-if="showConfirmLayer" :remark="remark" :task_id="task_id" :active-info="[activeInfo]" :show.sync="showConfirmLayer" :svipObj="svipObj" title="请核对申请奖品信息" @close="close" />
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { giftBagApply } from '@/api/game'
import { giftBagApply,selectSearch } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex'
import confirmLayer from '../confirmLayer'
export default {
......@@ -142,7 +156,7 @@ export default {
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'],
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading','task_id'],
data() {
return {
remark: '',
......@@ -155,7 +169,16 @@ export default {
num: '',
allpoints: 0,
showContent: true,
showConfirmLayer: false
benefitOptions:[],
showConfirmLayer: false,
svipObj: {
right_type: '',
select_type: ''
},
// 新增:1 充值日期 2 svip权益
select_type: 1,
// 权益类型选中的值
right_type: ''
}
},
......@@ -175,7 +198,18 @@ export default {
},
mounted() {
this.recharge_date_time = this.activeInfo.recharge_date
this.getBenefitOptions()
},
computed: {
// 根据选择类型显示对应的内容
showDatePicker() {
return this.select_type === 1
},
showBenefitSelect() {
return this.select_type === 2
}
},
methods: {
close() {
this.$emit('update:show', false)
......@@ -187,6 +221,50 @@ export default {
this.$emit('giftDetailsInfo', value)
}
},
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
const showList = ['月核心玩家礼包','超R生日福利礼包']
this.benefitOptions = res.data.data.filter((item, index) => {
return showList.includes(item.label)
}).map(item => ({
...item,
value: item.value || item.id // 确保每个选项都有value属性,优先使用value,不存在则使用id
}));
console.log(this.benefitOptions)
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
// 选择类型改变时触发
onSelectTypeChange() {
// 重置选择的值
if (this.select_type === 1) {
this.recharge_date_time = this.activeInfo.recharge_date
// 触发日期变化的接口
this.dateChange(this.recharge_date_time)
} else {
this.right_type = ''
}
},
// 权益类型改变时触发
onRightTypeChange() {
if (this.right_type) {
const data = {
right_type: this.right_type,
select_type: this.select_type
}
// 复用日期变化的接口
this.$emit('giftDetailsSVIPInfo', data)
}
},
openPrizeItem(item, index, value) {
console.log(item, index, value)
this.$set(this.giftInfo.rule.level_attribute[index], 'showContent', value)
......@@ -242,6 +320,8 @@ export default {
}
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
this.svipObj.right_type = this.right_type
this.svipObj.select_type = this.select_type
}
}
}
......@@ -360,6 +440,7 @@ export default {
left: 50%;
transform: translateX(-50%);
bottom: 100px;
z-index: 100;
}
.consumption-point{
font-size: 14px;
......
......@@ -57,7 +57,7 @@
<el-button size="small" class="btn" @click="close">取 消</el-button>
</span>
<!-- 确认弹窗 -->
<confirmLayer :is-submit="isSubmit" :remark="remark" :active-info="activeInfo" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
<confirmLayer :is-submit="isSubmit" :remark="remark" :task_id="task_id" :active-info="activeInfo" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
</div>
</el-drawer>
</template>
......@@ -72,7 +72,7 @@ export default {
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo','requestLoading'],
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo','requestLoading','task_id'],
data() {
return {
isSubmit: false,
......@@ -121,6 +121,7 @@ export default {
role_id,
remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '',
task_id: this.task_id || null,
create_user: this.cser_name,
rule: rule
}
......
......@@ -64,8 +64,30 @@
class="activeValue"
>{{ activeInfo.role_info.label }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">SVIP权益</div>
<div
v-if="giftInfo.rule?.right_type_name"
class="activeValue"
>{{ giftInfo.rule?.right_type_name || '-' }}</div>
</div>
<div class="rowFlex">
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: 70px">可领取次数</div>
<div
v-if="giftInfo.total_recharge"
class="activeValue"
>{{ giftInfo.total_recharge || '-' }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: 90px">剩余领取次数</div>
<div
v-if="giftInfo.real_score"
class="activeValue"
>{{ giftInfo.real_score || '-' }}</div>
</div>
</div>
<!-- 积分关的情况 -->
<div
v-if="activeInfo.gift_type == 2"
class="activeItem rowFlex"
......@@ -234,7 +256,7 @@
type="primary"
size="small"
:disabled="requestLoading"
@click="submit"
@click="submitBtn"
:loading="btnLoading"
>确 定</el-button>
<el-button
......@@ -247,6 +269,7 @@
<confirmLayer
v-if="showConfirmLayer"
:remark="remark"
:task_id="task_id"
:active-info="[activeInfo]"
:show.sync="showConfirmLayer"
title="请核对申请奖品信息"
......@@ -266,7 +289,7 @@ export default {
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'],
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading','task_id'],
data() {
return {
remark: '',
......@@ -385,7 +408,59 @@ export default {
handleChange() {
},
async submit() {
submitBtn(){
// svip 权益礼包
if(this.activeInfo.gift_type==7){
this.submitSvipGfit()
} else{
this.submitGift()
}
},
submitSvipGfit(){
this.loading = true
const role_id = this.activeInfo.role_info.value
// 直接处理activeInfo对象,避免不必要的数组包装和map操作
const activeInfo = this.activeInfo
let level_attribute = []
try {
// 安全地访问嵌套属性
if (this.giftInfo?.rule?.gift_type === 1) {
level_attribute = this.giftInfo.rule.level_attribute || []
} else if (this.giftInfo?.rule?.level_attribute) {
// 过滤出可申请的等级属性
level_attribute = this.giftInfo.rule.level_attribute.filter(item => item.apply_num > 0)
}
} catch (error) {
console.error('处理礼包等级属性时出错:', error)
// 出错时保持level_attribute为空数组
}
// 构建规则数据
const rule = [{ level_attribute, id: activeInfo.id }]
const data = {
role_id:role_id,
recharge_date:'',
remark: this.remark,
create_user: this.name,
task_id: this.task_id || null,
right_type: this.activeInfo.right_type || '',
select_type:this.activeInfo.gift_type==7?2:'',
rule: rule
}
giftBagApply(data).then(res => {
this.loading = false
if (res.status_code === 1) {
this.$message.success(res.msg)
this.close()
this.$emit('close')
} else {
this.close()
}
}, err => {
this.loading = false
})
},
async submitGift() {
this.btnLoading = true
const data = {
role_id: this.giftInfo.role_id,
......
<!--
* @Description: 发送邮件弹窗组件
* @Date: 2025-10-15
-->
<template>
<el-dialog
:visible.sync="dialogVisible"
title="发送邮件"
width="300px"
:close-on-click-modal="false"
:before-close="handleClose"
append-to-body
>
<el-form
ref="emailForm"
:model="formData"
:rules="formRules"
label-width="80px"
class="email-form"
>
<el-form-item label="邮件标题:" prop="email_title">
<el-input
v-model="formData.email_title"
placeholder="请输入邮件标题"
maxlength="100"
show-word-limit
clearable
/>
</el-form-item>
<el-form-item label="邮件内容:" prop="email_content">
<el-input
v-model="formData.email_content"
type="textarea"
:rows="8"
placeholder="请输入邮件内容"
maxlength="1000"
show-word-limit
clearable
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="handleClose">取消</el-button>
<el-button
type="primary"
:loading="sending"
@click="handleConfirm"
size="small"
>确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { sendEmail } from '@/api/game'
export default {
name: 'SendEmailDialog',
props: {
// 控制弹窗显示
visible: {
type: Boolean,
default: false
},
// 任务ID
taskId: {
type: [String, Number],
required: true
}
},
data() {
return {
// 弹窗显示状态
dialogVisible: false,
// 发送中状态
sending: false,
// 表单数据
formData: {
email_title: '',
email_content: ''
},
// 表单验证规则
formRules: {
email_title: [
{ required: true, message: '请输入邮件标题', trigger: 'blur' },
{ min: 1, max: 100, message: '邮件标题长度在 1 到 100 个字符', trigger: 'blur' }
],
email_content: [
{ required: true, message: '请输入邮件内容', trigger: 'blur' },
{ min: 1, max: 1000, message: '邮件内容长度在 1 到 1000 个字符', trigger: 'blur' }
]
}
}
},
watch: {
visible(val) {
this.dialogVisible = val
if (!val) {
// 关闭时重置表单
this.resetForm()
}
}
},
methods: {
/**
* 关闭弹窗
*/
handleClose() {
this.dialogVisible = false
this.$emit('update:visible', false)
this.resetForm()
},
/**
* 重置表单
*/
resetForm() {
this.formData = {
email_title: '',
email_content: ''
}
// 清除表单验证
this.$nextTick(() => {
this.$refs.emailForm && this.$refs.emailForm.clearValidate()
})
},
/**
* 确认发送邮件
*/
handleConfirm() {
// 表单验证
this.$refs.emailForm.validate((valid) => {
if (valid) {
this.sendEmailRequest()
} else {
console.log('表单验证失败')
return false
}
})
},
/**
* 发送邮件请求
*/
async sendEmailRequest() {
try {
this.sending = true
const params = {
id: this.taskId,
email_title: this.formData.email_title,
email_content: this.formData.email_content
}
const res = await sendEmail(params)
if (res.status_code === 1) {
this.$message({
message: res.msg || '邮件发送成功',
type: 'success'
})
// 通知父组件发送成功
this.$emit('send-success')
// 关闭弹窗
this.handleClose()
}
} catch (error) {
console.error('发送邮件失败:', error)
} finally {
this.sending = false
}
}
}
}
</script>
<style lang="scss" scoped>
.email-form {
::v-deep .el-form-item {
margin-bottom: 22px;
}
::v-deep .el-textarea__inner {
resize: vertical;
font-family: inherit;
}
::v-deep .el-input__count {
background-color: transparent;
}
}
.dialog-footer {
text-align: right;
padding: 10px 20px 0;
border: none;
.el-button {
min-width: 80px;
}
}
</style>
......@@ -184,16 +184,34 @@
</div>
</div>
</div>
<!-- 发送邮件按钮 -->
<!-- -->
<el-button
v-if="
kfhList.length == 0 && taskDetails.status != 3 && !is_finished
"
v-if="kfhList.length == 0 && assionInfo?.email?.is_send_email == 1 && !assionInfo?.email?.send_status && assionInfo.status != 3"
type="primary"
size="small"
style="margin-top: 20px; margin-right: 10px"
@click="showEmailDialog = true"
>发送邮件</el-button>
<!-- 礼包申请按钮 单日申请礼包任务和累充礼包申请时显示 -->
<!-- v-if="(assionInfo.plan_type == 19 || assionInfo.plan_type == 21) && assionInfo.status != 3" -->
<el-button
v-if="(assionInfo.plan_type == 19 || assionInfo.plan_type == 21) && assionInfo.status != 3"
type="primary"
size="small"
style="margin-top: 20px; margin-right: 10px"
:loading="loading"
@click="giftApply()"
>礼包申请</el-button>
<!-- 完成任务按钮 -->
<el-button
v-if="kfhList.length == 0 && taskDetails.status != 3 && !is_finished"
type="primary"
size="small"
style="margin-top: 20px"
@click="showLayer = true"
>完成任务</el-button
>
>完成任务</el-button>
</div>
</div>
</el-drawer>
......@@ -249,7 +267,10 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item label="备注:" prop="remark">
<el-form-item
label="备注:"
prop="remark"
>
<el-input
v-model="webForm.remark"
type="textarea"
......@@ -257,30 +278,53 @@
placeholder="备注请填写异常原因和异常类型,并列举后续维护策略/难以维护的原因"
></el-input>
</el-form-item>
</el-form>
</div>
</layer>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import {
<!-- 发送邮件弹窗 -->
<SendEmailDialog
:visible.sync="showEmailDialog"
:task-id="assionInfo.id"
@send-success="handleEmailSendSuccess"
/>
<!-- 礼包申请弹窗 -->
<applyGift
v-if="showApplyGift"
:show.sync="showApplyGift"
:member_id="assionInfo.member_id"
title="礼包申请"
width="25%"
:task_id="task_id"
@requestData="handleGiftApplySuccess"
/>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import {
taskRecord,
searchcondition,
memberOrder,
RoleTodayOrder,
taskDetails,
taskTrack,
} from '@/api/game';
import { memberBindExternalUser, clientSessionBindTaskApi } from '@/api/works';
import layer from '@/components/dialog.vue';
export default {
} from '@/api/game'
import { memberBindExternalUser } from '@/api/works'
import layer from '@/components/dialog.vue'
import SendEmailDialog from './SendEmailDialog.vue'
import applyGift from '@/views/components/giftRecord/applyGift.vue'
export default {
computed: {
...mapState('game', ['taskDetails']),
...mapState('user', ['userInfo', 'userid']),
...mapState('user', ['userInfo'])
},
components: {
layer,
SendEmailDialog,
applyGift
},
props: ['show'],
data() {
......@@ -296,20 +340,23 @@ export default {
assionInfo: {},
current: 0,
showLayer: false,
showEmailDialog: false, // 控制发送邮件弹窗显示
showApplyGift: false, // 控制礼包申请弹窗显示
task_id: null, // 礼包申请任务ID
dialogRemake: '',
webForm: {
trace_result: '',
remark: '',
abnormal_types: [],
abnormal_types: []
},
webFormRule: {
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
trace_result: [
{ required: true, message: '请选择跟进结果', trigger: 'change' },
{ required: true, message: '请选择跟进结果', trigger: 'change' }
],
abnormal_types: [
{ required: true, message: '请选择异常原因', trigger: 'change' },
],
{ required: true, message: '请选择异常原因', trigger: 'change' }
]
},
detailsList: [
{ label: '游戏名称', value: 'main_game_name' },
......@@ -469,63 +516,90 @@ export default {
console.log(res, '打开会话窗口成功');
},
fail: (err) => {
console.log(err, '打开会话窗口失败');
},
});
console.log(err, '打开会话窗口失败')
}
})
},
async memberOrder() {
let res = {};
let res = {}
if (!this.taskDetails.cp_role_id || this.taskDetails.cp_role_id == '') {
res = await memberOrder({ member_id: this.taskDetails.member_id });
res = await memberOrder({ member_id: this.taskDetails.member_id })
} else {
res = await RoleTodayOrder({ role_id: this.taskDetails.role_id });
res = await RoleTodayOrder({ role_id: this.taskDetails.role_id })
}
this.todayOrder = res.data[0];
this.assionInfo = { ...this.assionInfo, ...this.todayOrder };
this.todayOrder = res.data[0]
this.assionInfo = { ...this.assionInfo, ...this.todayOrder }
},
async taskRecord() {
const res = await taskRecord({
task_id: this.taskDetails.id,
user_type: '',
});
console.log(res.data.data, 'res.data.data');
if (res.data.data.length > 0) {
this.remarks = res.data.data[0].remarks;
} else {
this.remarks = [{ remark: '' }];
const res = await taskRecord({ task_id: this.taskDetails.id,user_type:'' })
console.log(res.data.data, 'res.data.data')
if(res.data.data.length > 0){
this.remarks = res.data.data[0].remarks
}else{
this.remarks = [{remark:''}]
}
},
async memberBindExternalUser() {
let member_list = [];
let member_list = []
if (this.assionInfo.members?.length > 0) {
member_list = this.assionInfo.members.map((item) => item.member_id);
member_list = this.assionInfo.members.map((item) => item.member_id)
} else {
member_list = [this.assionInfo.member_id];
member_list = [this.assionInfo.member_id]
}
this.loading = true;
this.loading = true
if (member_list.length === 0) {
return false;
return false
}
try {
const res = await memberBindExternalUser({
member_id: member_list.toString(),
is_bind: this.assionInfo.is_bind,
});
this.kfhList = res.data;
this.loading = false;
is_bind: this.assionInfo.is_bind
})
this.kfhList = res.data
this.loading = false
} catch (error) {
this.loading = false;
this.loading = false
}
},
/**
* 处理邮件发送成功的回调
* 设置任务的邮件发送状态为已发送
*/
handleEmailSendSuccess() {
// 标记任务已发送邮件
this.assionInfo.send_status = 1
// 可以选择刷新任务详情
// this.requestTaskDetails()
},
};
</script>
/**
* 显示礼包申请弹窗
* @param {Object} item - 任务信息对象,包含任务ID
*/
giftApply() {
this.task_id = this.assionInfo.id || null
this.showApplyGift = true
},
/**
* 处理礼包申请完成后的回调
* 关闭弹窗并显示成功提示
*/
handleGiftApplySuccess() {
this.showApplyGift = false
this.$message({
message: '礼包申请已提交',
type: 'success'
})
}
}
}
</script>
<style lang="scss" scoped>
.contet {
height: 100%;
background: #fff;
padding: 10px;
overflow: auto;
.title {
font-size: 14px;
......@@ -534,7 +608,6 @@ export default {
color: #333333;
margin-bottom: 10px;
}
.taskInfo {
height: auto;
background: #f7f8fa;
......
......@@ -76,9 +76,11 @@
</div>
</div>
<div class="btns rowFlex allCenter" style="margin-top: 20px">
<el-button :disabled="item.status == 3" :loading="remarkLoading"
<el-button size="small" :disabled="item.status == 3" :loading="remarkLoading"
@click="saveRemak(item, index)">保存</el-button>
<el-button type="primary" :disabled="item.status == 3" :loading="taskLoading"
<!-- 单日申请礼包任务才展示礼包申请按钮 v-if="item.plan_type == 19 || item.plan_type == 21" 新增 累充礼包申请时 和 单日礼包申请一样 显示 礼包申请按钮 -->
<el-button type="primary" size="small" v-if="item.plan_type == 19 || item.plan_type == 21" :loading="taskLoading" @click="giftApply(item)">礼包申请</el-button>
<el-button type="primary" size="small" :disabled="item.status == 3" :loading="taskLoading"
@click="completeTask(item, index)">保存并完成任务</el-button>
</div>
</el-collapse-item>
......@@ -92,6 +94,15 @@
</div>
</div>
</div>
<!-- 礼包申请弹窗 -->
<applyGift
v-if="showApplyGift"
:show.sync="showApplyGift"
title="礼包申请"
width="25%"
:task_id="task_id"
@requestData="handleGiftApplySuccess"
/>
</div>
</template>
<script>
......@@ -99,10 +110,12 @@
import { mapState } from 'vuex'
import textEditor from '@/components/textEditor.vue'
import noContent from '@/components/noContent.vue'
import applyGift from '@/views/components/giftRecord/applyGift.vue'
export default {
components: {
textEditor,
noContent,
applyGift
},
data() {
return {
......@@ -131,6 +144,8 @@
showLayer: false,
taskLoading: false,
remarkLoading: false,
showApplyGift: false,
task_id: null,
pageInfo: {
page: 0,
page_size: 20,
......@@ -190,6 +205,24 @@
this.searchconditionError()
},
methods: {
/**
* 显示礼包申请弹窗
*/
giftApply(item) {
this.task_id = item.id || null
this.showApplyGift = true
},
/**
* 处理礼包申请完成后的回调
* 关闭弹窗并显示成功提示
*/
handleGiftApplySuccess() {
this.showApplyGift = false
this.$message({
message: '礼包申请已提交',
type: 'success'
})
},
searchcondition() {
const data = {
type: 'dictionaries',
......
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-10-31 15:00:00
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-10-31 17:18:17
* @FilePath: /company_wx_frontend/src/components/common/game/benefitUsageRecord.vue
* @Description: 权益使用记录组件
-->
<template>
<div class="benefit-usage-record">
<!-- 搜索区域 -->
<div class="search-content">
<el-form label-position="top" :model="formData" class="search-form">
<el-form-item label="权益">
<el-select
v-model="formData.type"
clearable
placeholder="请选择权益"
@change="handleTypeChange"
style="width:100%;"
>
<el-option
v-for="item in benefitOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="时间范围">
<el-date-picker
v-model="formData.dateRange"
type="datetimerange"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
:default-time="['00:00:00', '23:59:59']"
style="width:100%;"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:loading="loading"
@click="startSearch"
>
搜索
</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 表格区域 -->
<div class="table-container">
<el-table
v-loading="loading"
:data="tableData"
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
>
<el-table-column
label="角色名称/cp角色Id"
min-width="200"
>
<template slot-scope="scope">
<p>{{ scope.row.role_name }}</p>
<p class="infoText">{{ scope.row.cp_role_id }}</p>
</template>
</el-table-column>
<el-table-column
label="权益"
prop="type_name"
min-width="150"
/>
<el-table-column
label="使用人"
prop="create_user"
min-width="120"
/>
<el-table-column
label="使用时间"
prop="create_time"
min-width="180"
/>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
:current-page="page_info.page"
:page-sizes="[10, 20, 50, 100]"
:page-size="page_info.page_size"
layout="total, sizes, prev, pager, next, jumper"
:total="page_info.total"
/>
</div>
</div>
</div>
</template>
<script>
import { useRightList,selectSearch } from '@/api/game'
export default {
name: 'BenefitUsageRecord',
props: {
benefitItem: {
type: Object,
default: () => ({})
},
roleInfo: {
type: Object,
default: () => ({})
}
},
data() {
return {
loading: false,
formData: {
type: '',
dateRange: []
},
benefitOptions: [],
tableData: [],
tableColums: [
{
label: '角色名称/cp角色Id',
prop: 'role_info',
minWidth: 200,
slotScope: true
},
{
label: '权益',
prop: 'type_name',
minWidth: 150
},
{
label: '使用人',
prop: 'create_user',
minWidth: 120,
},
{
label: '使用时间',
prop: 'create_time',
minWidth: 180
}
],
page_info: {
page: 1,
page_size: 20,
total: 0
}
}
},
mounted() {
this.getBenefitOptions()
this.getTableData()
},
methods: {
/**
* 获取权益下拉选项
*/
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
this.benefitOptions = res.data.data
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
/**
* 获取表格数据
*/
async getTableData() {
try {
this.loading = true
const requestData = {
cp_role_id: this.roleInfo.cp_role_id,
type: this.formData.type,
create_time_start: this.formData.dateRange && this.formData.dateRange.length > 0 ? this.formData.dateRange[0] : '',
create_time_end: this.formData.dateRange && this.formData.dateRange.length > 0 ? this.formData.dateRange[1] : '',
page: this.page_info.page,
page_size: this.page_info.page_size
}
const res = await useRightList(requestData)
if (res.status_code === 1) {
this.tableData = res.data.data || []
this.page_info.total = Number(res.data.page_info.total) || 0
} else {
this.$message({
message: res.data.msg || '获取数据失败',
type: 'error'
})
}
} catch (error) {
console.error('获取权益使用记录失败:', error)
this.$message({
message: '获取数据失败,请重试',
type: 'error'
})
} finally {
this.loading = false
}
},
/**
* 处理页码变化
*/
handleCurrentChange(currentPage) {
this.page_info.page = currentPage
this.getTableData()
},
/**
* 处理每页条数变化
*/
handleSizeChange(pageSize) {
this.page_info.page_size = pageSize
this.page_info.page = 1
this.getTableData()
},
/**
* 处理权益类型变化
*/
handleTypeChange() {
this.page_info.page = 1
this.getTableData()
},
/**
* 开始搜索
*/
startSearch() {
this.page_info.page = 1
this.getTableData()
},
/**
* 重置表单
*/
resetForm() {
this.formData = {
type: '',
dateRange: []
}
this.startSearch()
}
}
}
</script>
<style lang="scss" scoped>
.benefit-usage-record {
::v-deep .el-table__header-wrapper{
position: static;
top: 0;
}
.search-content {
padding: 20px;
background: #fff;
border-radius: 4px;
max-height: 80%;
overflow: auto;
.search-form {
.el-form-item {
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
}
}
}
.table-container {
background: #fff;
border-radius: 4px;
padding: 20px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.infoText {
color: #c9cdd4;
font-size: 12px;
margin-top: 4px;
}
}
</style>
......@@ -2,7 +2,7 @@
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-09-13 14:05:01
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-09-22 17:24:19
* @LastEditTime: 2025-10-31 17:01:13
* @FilePath: /company_wx_frontend/src/views/works/component/gameInfo/vipLevel.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
......@@ -16,7 +16,7 @@
:disabled="loading"
>
<!-- 最大宽度 400px -->
<div class="vipLevelContent" style="max-width: 400px;max-height: 300px;overflow: auto;">
<div class="vipLevelContent" style="min-width:250px;">
<div v-if="loading" class="loading-content">
<i class="el-icon-loading"></i>
<span>加载中...</span>
......@@ -25,7 +25,19 @@
<div class="vipLevelItem rowFlex columnCenter" v-for="(item,index) in vipLevelBenefit" :key="index">
<p class="vipLevelItemRow" v-if="item.num" :style="{color: item.target ? '#333333' : '#c9cdd4'}" >
<span v-if="item.name" class="label">{{item.name}} </span>
<span v-if="item.num" :style="{color: item.target ? '#00bf8a' : '#c9cdd4'}" class="value"> {{item.num }}</span>
<!-- 人工权益显示使用按钮 -->
<div v-if="item.monitor_type === 2" class="benefit-actions">
<el-button
type="primary"
size="mini"
style="margin-left: 10px;"
:disabled="!item.target"
@click.stop="handleUseBenefit(item)"
class="use-button"
>
使用
</el-button>
</div>
</p>
</div>
<div v-if="vipLevelBenefit.length === 0" class="no-data">
......@@ -37,11 +49,62 @@
<span class="vipLevelText" v-if="vip_role_info.vip_level" @click.stop="showVipLevel">{{ `SVIP等级${vip_role_info.vip_level}` }}</span>
</div>
</el-popover>
<!-- 使用权益确认弹窗 -->
<el-dialog
v-if="useBenefitDialogVisible"
title="确认提示"
:visible.sync="useBenefitDialogVisible"
width="400px"
:before-close="handleDialogClose"
>
<div class="dialog-content">
<div class="rowFlex columnCenter">
<i class="el-icon-warning" style="color: #E6A23C; font-size: 24px; margin-right: 10px;"></i>
<span>是否确认使用{{ currentBenefitItem?.name }}权益?</span>
</div>
<p class="text-center" style="color: #999; font-size: 14px; margin-top: 10px;">点击确定后,权益剩余使用数量将减 1</p>
</div>
<div slot="footer" >
<el-button
type="text"
@click="showUsageRecordFromDialog"
class="record-button"
>
使用记录
</el-button>
<el-button @click="handleDialogClose">取消</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirmUseBenefit"
>
确认
</el-button>
</div>
</el-dialog>
<!-- 使用记录弹窗 -->
<el-dialog
title="权益使用记录"
:visible.sync="usageRecordVisible"
width="80%"
:before-close="closeUsageRecord"
append-to-body
@close="closeUsageRecord"
>
<BenefitUsageRecord
:benefit-item="currentBenefitItem"
:role-info="vip_role_info"
/>
</el-dialog>
</div>
</template>
<script>
import { marketingRoleGradeBenefit,marketingMemberRoleGrade } from '@/api/game'
import { marketingRoleGradeBenefit,marketingMemberRoleGrade,useBenefit } from '@/api/game'
import { mapState, mapMutations } from 'vuex'
import BenefitUsageRecord from './benefitusageRecord.vue'
export default {
name: 'VipLevel',
data() {
......@@ -49,9 +112,15 @@ export default {
vip_role_info: {},
vipLevelBenefit: [],
popoverVisible: false,
loading: false
loading: false,
usageRecordVisible: false,
currentBenefitItem: null,
useBenefitDialogVisible: false
}
},
components: {
BenefitUsageRecord
},
props: {
roleInfo: {
type: Object,
......@@ -73,7 +142,8 @@ export default {
}
},
computed: {
...mapState('game', ['accountSelect'])
...mapState('game', ['accountSelect']),
...mapState('user', ['userInfo']),
},
methods: {
async marketingMemberRoleGrade() {
......@@ -134,7 +204,80 @@ export default {
// 获取数据并显示popover
await this.getVipLevel();
},
/**
* 处理使用权益
*/
handleUseBenefit(item) {
this.currentBenefitItem = item;
this.useBenefitDialogVisible = true;
},
/**
* 确认使用权益
*/
async confirmUseBenefit() {
try {
this.loading = true;
const requestData = {
role_id: this.vip_role_info.role_id,
grade_config_id: this.currentBenefitItem.grade_config_id,
user_name:this.userInfo.username
};
const res = await useBenefit(requestData);
if (res.status_code === 1) {
this.$message({
message: res.data.msg || '使用成功',
type: 'success'
});
// 直接更新本地权益数据
const benefitIndex = this.vipLevelBenefit.findIndex(item =>
item.grade_config_id === this.currentBenefitItem.grade_config_id
);
if (benefitIndex !== -1) {
this.vipLevelBenefit[benefitIndex].remain_num -= 1;
}
this.useBenefitDialogVisible = false;
this.currentBenefitItem = null;
} else {
this.$message({
message: res.data.msg || '使用失败',
type: 'error'
});
}
} catch (error) {
console.error('使用权益失败:', error);
} finally {
this.loading = false;
}
},
/**
* 处理dialog关闭
*/
handleDialogClose() {
this.useBenefitDialogVisible = false;
this.currentBenefitItem = null;
},
/**
* 从dialog中显示使用记录弹窗
*/
showUsageRecordFromDialog() {
this.usageRecordVisible = true;
this.useBenefitDialogVisible = false;
},
/**
* 关闭使用记录弹窗
*/
closeUsageRecord() {
this.usageRecordVisible = false;
this.currentBenefitItem = null;
}
}
}
</script>
......@@ -185,8 +328,54 @@ export default {
.value {
font-weight: bold;
}
.benefit-actions {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
.use-button {
margin-left: 10px;
}
.record-button {
font-size: 12px;
padding: 0;
}
}
}
}
}
.dialog-content {
font-size: 16px;
color: #333;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
.record-button {
margin-left: 10px;
color: #409EFF;
cursor: pointer;
&:hover {
color: #66b1ff;
}
}
}
// 使用记录弹窗样式
.el-dialog {
::v-deep .el-dialog__body {
padding: 0;
max-height: 70vh;
overflow-y: auto;
}
}
}
</style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论