提交 ded7e8cc 作者: 毛细亚

优化组件样式与交互

上级 108e1d81
<!--
# getRoleList 传入 member_id 获取角色列表
-->
<template>
<el-select v-model="selectedValue" placeholder="请选择" clearable size="small" :style="{ width: width || '100%' }"
v-bind="$attrs" :clearable="false" filterable remote :remote-method="remoteMethod" @clear="handleClear"
v-on="$listeners" @change="handleChange" @visible-change="handleVisibleChange">
<div class="select-dropdown" @scroll="handleScroll">
<el-option v-for="item in RuleList" :key="item.value" :label="item.label" :value="item.value"></el-option>
<div v-if="loading" v-loading="true" class="loading-more">
加载中...
</div>
</div>
</el-select>
</template>
<script lang="jsx">
import { getRoleHoLo } from '@/api/game'
import { debounce } from '@/utils'
export default {
name: 'getRoleList',
props: {
member_id: {
type: [String, Number],
default: ''
},
value: {
type: [String, Number],
default: ''
},
width: {
type: [String, Number],
default: ''
}
},
data() {
return {
RuleList: [],
loading: false,
currentPage: 1,
hasMore: true,
searchQuery: '',
selectedValue: this.value,
_debouncedRemote: null
}
},
watch: {
value(newVal) {
this.selectedValue = newVal
},
member_id(newVal) {
this.getRuleList()
}
},
created() {
this.getRuleList()
},
methods: {
async getRuleList(isLoadMore = false, query) {
// 仅在加载更多时受 hasMore 限制;新检索应始终允许
if (this.loading || (isLoadMore && !this.hasMore)) return
try {
this.loading = true
const keyword = typeof query === 'string' ? query : this.searchQuery
if (!isLoadMore) {
// 新检索时记录关键字
this.searchQuery = keyword || ''
}
const res = await getRoleHoLo({
page: isLoadMore ? this.currentPage + 1 : 1,
page_size: 20,
api_search_name: keyword,
search_type: 'list',
member_id: this.member_id
})
if (res.status_code === 1 && res.data && res.data.data) {
res.data.data.forEach(item => {
item.server_name ? item.label = `${item.role_name} - ${item.server_name}` : item.label = item.role_name
item.value = item.role_id
})
if (isLoadMore) {
this.RuleList = [...this.RuleList, ...res.data.data]
this.currentPage++
} else {
this.RuleList = res.data.data
this.currentPage = 1
}
this.hasMore = res.data.data.length >= 20
} else {
this.$message.warning(res.data.msg)
}
} catch (error) {
this.$message.error('获取数据失败')
} finally {
this.loading = false
}
},
handleScroll(e) {
const { scrollTop, scrollHeight, clientHeight } = e.target
if (scrollHeight - scrollTop - clientHeight < 50 && this.hasMore) {
this.getRuleList(true, this.searchQuery)
}
},
handleClear() {
this.selectedValue = ''
this.searchQuery = ''
this.$emit('clear')
},
handleChange() {
const roleInfo = this.RuleList.find(item => item.value === this.selectedValue)
this.$emit('selectChange', roleInfo)
},
handleVisibleChange(visible) {
// if (visible) {
// this.getRuleList()
// }
},
remoteMethod(query) {
if (!this._debouncedRemote) {
this._debouncedRemote = debounce((q) => {
this.getRuleList(false, q)
}, 300)
}
this._debouncedRemote(query)
}
}
}
</script>
<style lang="scss" scoped>
.select-dropdown {
max-height: 300px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: #e4e7ed;
border-radius: 3px;
}
}
.loading-more {
text-align: center;
padding: 5px 0;
}
</style>
\ No newline at end of file
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-08-28 15:59:46
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-08-30 11:35:36
* @FilePath: /company_wx_frontend/src/views/works/component/chat/giftCodeDialog.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<el-dialog title="礼包码" :visible="dialogVisible" class="giftCodeDialogForm" width="500px" @close="closeDialog">
<el-form :model="form" ref="giftCodeDialogForm" label-width="120px" :rules="rules">
<el-form-item label="账号ID" prop="member_id">
<el-select style="width: 320px;" :clearable="false" @change="handleMemberIdChange"
v-model="form.member_id" placeholder="请选择账号ID">
<el-option v-for="item in bindGameUserList" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="角色ID" prop="role_id">
<getRoleList v-model="form.role_id" width="320px" placeholder="请选择角色" :member_id="form.member_id"
@selectChange="handleSelectionChange" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="getGiftCodeSubmit('send')">确定</el-button>
<el-button type="text" @click="getGiftCodeSubmit('copy')">仅复制</el-button>
</div>
</el-dialog>
</template>
<script>
import getRoleList from '@/components/getRoleList.vue'
import { getRoleHoLo } from '@/api/game'
import { mapState } from 'vuex'
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
}
},
components: {
getRoleList
},
data() {
return {
form: {
member_id: '',
username: '',
role_id: '',
role_name: '',
},
rules: {
member_id: [{ required: true, message: '请选择账号ID', trigger: 'change' }],
role_id: [{ required: true, message: '请选择角色ID', trigger: 'change' }]
},
getRoleHoLo: getRoleHoLo,
gift_code: [],
roleList: [],
pageInfo: {
page: 1,
page_size: 10
},
loading: false
}
},
mounted() {
this.form.member_id = this.accountSelect
this.form.username = this.bindGameUserList.find(item => item.member_id === this.accountSelect).username
},
computed: {
...mapState('game', ['accountSelect', 'bindGameUserList'])
},
methods: {
handleMemberIdChange(value) {
this.form.role_id = ''
this.form.role_name = ''
const userInfo = this.bindGameUserList.find(item => item.value === value)
this.form.username = userInfo.label || userInfo.username
this.form.member_id = value
},
handleSelectionChange(roleInfo) {
console.log(roleInfo, 'roleInfo')
this.form.role_name = roleInfo.label || ''
},
closeDialog() {
this.$emit('update:dialogVisible', false)
},
getGiftCodeSubmit(type) {
this.$refs.giftCodeDialogForm.validate((valid) => {
if (valid) {
this.$emit('update:dialogVisible', false)
this.$emit('result', this.form, type)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.giftCodeDialogForm {
.dialog-footer {
border: none;
padding: 0;
}
}
</style>
\ No newline at end of file
...@@ -59,12 +59,14 @@ ...@@ -59,12 +59,14 @@
</el-collapse> </el-collapse>
</el-collapse-transition> </el-collapse-transition>
</div> </div>
<giftCodeDialog ref="giftCodeDialog" :dialogVisible="dialogVisible" @result="getGiftCodeSubmit" />
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import { passwardEncryption, createVipUrl } from '@/api/game' import { passwardEncryption, createVipUrl } from '@/api/game'
import { giftCodeList, sendGiftCode, getZyouAuthLink } from '@/api/works' import { giftCodeList, sendGiftCode, getZyouAuthLink } from '@/api/works'
import giftCodeDialog from './giftCodeDialog.vue'
export default { export default {
name: 'vipTools', name: 'vipTools',
data() { data() {
......
<template> <template>
<div class="details-user-info-role columnFlex"> <div class="details-user-info-role columnFlex">
<div <div v-loading="loading" class="detailsContent">
v-loading="loading" <div v-if="roleList.length > 0">
class="detailsContent" <p class="textInfo">角色充值金额信息会有5-10分钟延迟,请以订单信息为准</p>
> <el-collapse v-model="collapseActive" @change="handleChange">
<div v-if="roleList.length>0"> <div v-for="(items, indexs) in roleList" :key="indexs" class="contentItem mb-[10px]">
<p class="textInfo">角色充值金额信息会有5-10分钟延迟,请以订单信息为准</p> <div class="title"></div>
<el-collapse <el-collapse-item :name="items.id">
v-model="collapseActive" <template slot="title">
@change="handleChange" <div class="collapseTitle rowFlex columnCenter spaceBetween">
> <p class="hidden">
<div {{ items.role_name }} - {{ items.server_name }} - {{
v-for="(items,indexs) in roleList" items.recharge_total ? items.recharge_total + '元' : '0元' }}
:key="indexs" </p>
class="contentItem" <el-button type="primary" size="mini" class="collapseTitleBtn"
> @click.stop="appealLayer(items)">申诉</el-button>
<div class="title"></div>
<el-collapse-item :name="items.id">
<template slot="title">
<div class="collapseTitle rowFlex columnCenter spaceBetween">
<p class="hidden">
{{ items.role_name }} - {{ items.server_name }} - {{ items.recharge_total?items.recharge_total+'元':'0元' }}
</p>
<el-button
type="primary"
size="mini"
class="collapseTitleBtn"
@click.stop="appealLayer(items)"
>申诉</el-button>
</div>
</template>
<div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter">
<span class="label">区服:</span>
<p class="text">{{ items.server_name }}</p>
</div>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </template>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">合区区服:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.merge_server_name }}</p> <span class="label">区服:</span>
</div> <p class="text">{{ items.server_name }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">角色名称:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.role_name }}</p> <span class="label">合区区服:</span>
</div> <p class="text">{{ items.merge_server_name }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">等级:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.role_level }}</p> <span class="label">角色名称:</span>
</div> <p class="text">{{ items.role_name }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">战力:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.combat_num }}</p> <span class="label">等级:</span>
</div> <p class="text">{{ items.role_level }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">充值金额:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.recharge_total }}</p> <span class="label">战力:</span>
</div> <p class="text">{{ items.combat_num }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">转端审核:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.trans_status_name || '无' }}</p> <span class="label">充值金额:</span>
</div> <p class="text">{{ items.recharge_total }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">CP角色ID:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.cp_role_id }}</p> <span class="label">转端审核:</span>
</div> <p class="text">{{ items.trans_status_name || '无' }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">最近活跃时间:</span> <div class="rowFlex columnCenter">
<p class="text">{{ $moment( items.last_login_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}</p> <span class="label">CP角色ID:</span>
</div> <p class="text">{{ items.cp_role_id }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">创建时间:</span> <div class="rowFlex columnCenter">
<p class="text">{{ $moment( items.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}</p> <span class="label">最近活跃时间:</span>
</div> <p class="text">{{ $moment(items.last_login_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}</p>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> </div>
<div class="rowFlex columnCenter"> <div class="item rowFlex columnCenter spaceBetween">
<span class="label">创角天数:</span> <div class="rowFlex columnCenter">
<p class="text">{{ items.create_role_day }}天</p> <span class="label">创建时间:</span>
</div> <p class="text">{{ $moment(items.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}</p>
</div> </div>
</el-collapse-item> </div>
</div> <div class="item rowFlex columnCenter spaceBetween">
</el-collapse> <div class="rowFlex columnCenter">
</div> <span class="label">创角天数:</span>
<div <p class="text">{{ items.create_role_day }}天</p>
v-else-if="!loading && roleList.length==0" </div>
class="noContent rowFlex allCenter" </div>
> </el-collapse-item>
<noContent title="暂无数据" description="当前没有任何数据,请稍后再试或联系管理员" /> </div>
</div> </el-collapse>
</div>
<div v-else-if="!loading && roleList.length == 0" class="noContent rowFlex allCenter">
<noContent title="暂无数据" description="当前没有任何数据,请稍后再试或联系管理员" />
</div> </div>
<appeal
v-if="showAppeal"
:show.sync="showAppeal"
:appeal-info="appealInfo"
/>
</div> </div>
</template> <appeal v-if="showAppeal" :show.sync="showAppeal" :appeal-info="appealInfo" />
</div>
<script> </template>
import { mapState, mapMutations, mapActions } from 'vuex'
import { getRoleHoLo } from '@/api/game' <script>
import noContent from '@/components/noContent.vue' import { mapState, mapMutations, mapActions } from 'vuex'
import appeal from './layer/appeal.vue' import { getRoleHoLo } from '@/api/game'
import watchMember from '@/mixins/watchMember' import noContent from '@/components/noContent.vue'
export default { import appeal from './layer/appeal.vue'
name: 'roleInfo', import watchMember from '@/mixins/watchMember'
components: { export default {
noContent, name: 'roleInfo',
appeal components: {
}, noContent,
data() { appeal
return { },
collapseActive: [], data() {
roleList: [], return {
nowTime: '', collapseActive: [],
loading: false, roleList: [],
showAppeal: false, nowTime: '',
appealInfo: {}, loading: false,
pageInfo: { showAppeal: false,
page_size: 100, appealInfo: {},
page: 1, pageInfo: {
total: 0 page_size: 100,
}, page: 1,
infoList: [] total: 0
} },
}, infoList: []
computed: { }
...mapState('game', ['accountSelect']) },
computed: {
...mapState('game', ['accountSelect'])
},
mixins: [watchMember],
mounted() {
this.requestRoleList()
this.nowTime = new Date().getTime()
},
methods: {
handleChange() {
}, },
mixins: [watchMember], memberChange() {
mounted() {
this.requestRoleList() this.requestRoleList()
this.nowTime = new Date().getTime()
}, },
methods: { // 申诉
handleChange() { appealLayer(item) {
this.appealInfo = item
}, this.showAppeal = true
memberChange() { },
this.requestRoleList() requestRoleList() {
}, if (this.accountSelect === '') {
// 申诉 this.$message.warning('暂无关联的账号,请先去关联账号!')
appealLayer(item) { return false
this.appealInfo = item }
this.showAppeal = true this.loading = true
}, const data = {
requestRoleList() { api_search_name: '',
if (this.accountSelect === '') { member_id: this.accountSelect,
this.$message.warning('暂无关联的账号,请先去关联账号!') search_type: 'list',
return false ...this.pageInfo
}
this.loading = true
const data = {
api_search_name: '',
member_id: this.accountSelect,
search_type: 'list',
...this.pageInfo
}
getRoleHoLo(data).then(res => {
this.loading = false
if (res.status_code == 1) {
if (res.data.data.length > 0) {
this.roleList = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) })
} else {
this.roleList = []
}
}
}, err => {
this.loading = false
})
} }
getRoleHoLo(data).then(res => {
this.loading = false
if (res.status_code == 1) {
if (res.data.data.length > 0) {
this.roleList = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) })
} else {
this.roleList = []
}
}
}, err => {
this.loading = false
})
}
}
}
</script>
<style lang="scss" scoped>
.details-user-info-role {
width: 100%;
height: 100%;
background: #fff;
margin-left: 2px;
overflow: auto;
.detailsTitle {
width: 100%;
padding: 0 10px;
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
border-bottom: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
p {
color: #333333;
} }
} }
</script>
<style lang="scss" scoped> .detailsContent {
.details-user-info-role {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #fff;
margin-left: 2px;
overflow: auto; overflow: auto;
.detailsTitle {
width: 100%; .textInfo {
padding: 0 10px; font-family: PingFangSC-Regular, PingFang SC;
height: 60px; font-weight: 400;
font-size: 18px; color: #999999;
font-family: PingFangSC-Medium, PingFang SC; font-size: 12px;
font-weight: 500; margin-bottom: 10px;
color: #333333; margin-top: 10px;
border-bottom: 1px solid #ebeef5; }
border-left: 1px solid #ebeef5;
p { .contentItem {
color: #333333; position: relative;
.title {
position: absolute;
left: 10px;
top: 14px;
font-size: 14px;
color: #999999;
}
.collapseTitle {
width: 90%;
} }
} }
.detailsContent {
.item {
width: 100%; width: 100%;
height: 100%; height: auto;
overflow: auto; font-size: 14px;
.textInfo { font-weight: 400;
font-family: PingFangSC-Regular, PingFang SC; color: #333333;
font-weight: 400; padding: 5px 0;
color: #999999; transition: all 0.5s;
font-size: 12px; position: relative;
margin-bottom: 10px; padding-left: 10px;
margin-top: 10px; cursor: pointer;
.tableImage {
width: 40px;
height: 40px;
border-radius: 6px;
margin-right: 10px;
} }
.contentItem {
position: relative; .label {
.title { color: #999999;
position: absolute;
left: 10px;
top: 14px;
font-size: 14px;
color: #999999;
}
.collapseTitle {
width: 90%;
}
} }
.item {
width: 100%; .text {
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333; color: #333333;
padding: 5px 0; margin-left: 10px;
transition: all 0.5s; word-break: break-all;
position: relative; max-width: 80%;
padding-left: 10px; }
cursor: pointer;
.tableImage { .icon {
width: 40px; display: none;
height: 40px; position: absolute;
border-radius: 6px; right: 0;
margin-right: 10px; top: 12px;
} }
.label {
color: #999999; .tags {
width: 300px;
margin-left: 10px;
.tagsItem {
width: 300px;
} }
.text {
.tag {
height: 22px;
line-height: 22px;
padding: 0 8px;
background: #ffffff;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333; color: #333333;
margin-left: 10px; margin-right: 10px;
word-break: break-all; margin-bottom: 10px;
max-width: 80%;
}
.icon {
display: none;
position: absolute;
right: 0;
top: 12px;
}
.tags {
width: 300px;
margin-left: 10px;
.tagsItem {
width: 300px;
}
.tag {
height: 22px;
line-height: 22px;
padding: 0 8px;
background: #ffffff;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
margin-right: 10px;
margin-bottom: 10px;
}
} }
} }
.item:hover .icon {
display: block;
}
} }
/* 已移除局部 el-collapse 样式,使用全局样式 */
.item:hover .icon {
display: block;
}
} }
</style>
\ No newline at end of file /* 已移除局部 el-collapse 样式,使用全局样式 */
}
</style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论