增加游戏ip屏蔽的配置

This commit is contained in:
zhl 2020-11-11 15:29:12 +08:00
parent feeb88c16a
commit d29bc132d5
7 changed files with 442 additions and 31 deletions

View File

@ -16,6 +16,7 @@
"dependencies": { "dependencies": {
"axios": "0.18.0", "axios": "0.18.0",
"echarts": "^4.2.1", "echarts": "^4.2.1",
"el-tree-transfer": "^2.3.2",
"element-ui": "^2.9.1", "element-ui": "^2.9.1",
"install": "^0.12.2", "install": "^0.12.2",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",

View File

@ -10,6 +10,14 @@ export function getRegions(params) {
}) })
} }
export function getRegionWithId(params) {
return request({
url: '/common/loc/china_region_id',
method: 'get',
params,
})
}
export function getAreas() { export function getAreas() {
return request({ return request({
url: '/common/loc/china_area', url: '/common/loc/china_area',

View File

@ -57,7 +57,6 @@ export function deployCfg(data) {
}) })
} }
export function updateRC(data) { export function updateRC(data) {
return request({ return request({
url: '/games/update_rc', url: '/games/update_rc',
@ -65,3 +64,19 @@ export function updateRC(data) {
data data
}) })
} }
export function getIpInfo(gid, pid) {
const url = `/games/ip/${gid}/${pid}`
return request({
url: url,
method: 'get',
})
}
export function saveIpInfo(data) {
return request({
url: '/games/ip/update',
method: 'post',
data
})
}

View File

@ -112,6 +112,12 @@ const gamesRouter = {
name: 'GameDetailsBanner', name: 'GameDetailsBanner',
meta: { title: 'Banner广告配置' } meta: { title: 'Banner广告配置' }
}, },
{
path: 'settings/ip',
component: () => import('@/views/games/details/settings/ip'),
name: 'GameDetailsIP',
meta: { title: 'IP屏蔽' }
},
{ {
path: 'recommendation', path: 'recommendation',
component: () => import('@/views/games/details/recommendation'), component: () => import('@/views/games/details/recommendation'),

View File

@ -21,6 +21,7 @@
<el-menu-item :index="`/games/details/${uid}/settings/sign`">签到</el-menu-item> <el-menu-item :index="`/games/details/${uid}/settings/sign`">签到</el-menu-item>
<el-menu-item :index="`/games/details/${uid}/settings/online`">在线</el-menu-item> <el-menu-item :index="`/games/details/${uid}/settings/online`">在线</el-menu-item>
<el-menu-item :index="`/games/details/${uid}/settings/banner`">banner</el-menu-item> <el-menu-item :index="`/games/details/${uid}/settings/banner`">banner</el-menu-item>
<el-menu-item :index="`/games/details/${uid}/settings/ip`">IP屏蔽</el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item <el-menu-item
v-if="uid !== 'new'" v-if="uid !== 'new'"

View File

@ -14,7 +14,7 @@
style="color: #E6A23C" style="color: #E6A23C"
>{{ >{{
tip tip
}}</span> }}</span>
</div> </div>
<el-form <el-form
ref="settingForm" ref="settingForm"
@ -59,10 +59,10 @@
trigger: 'blur' trigger: 'blur'
}" }"
> >
<span slot="label">{{item.title}} <span slot="label">{{ item.title }}
<span <span
class="tip-wrap"
v-if="settingsCommentList[item.key]" v-if="settingsCommentList[item.key]"
class="tip-wrap"
> >
<el-tooltip <el-tooltip
class="item" class="item"
@ -71,7 +71,7 @@
placement="top" placement="top"
:disabled="!settingsCommentList[item.key]" :disabled="!settingsCommentList[item.key]"
> >
<svg-icon icon-class="question" /> <svg-icon icon-class="question"/>
</el-tooltip> </el-tooltip>
</span> </span>
</span> </span>
@ -117,13 +117,13 @@
>发布</el-button> >发布</el-button>
<el-button <el-button
v-if="permEdit" v-if="permEdit"
@click="reset"
type="success" type="success"
@click="reset"
>重置</el-button> >重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="divider" /> <div class="divider"/>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<div class="al-c"> <div class="al-c">
@ -137,16 +137,16 @@
class="mgb-20 multiple-select" class="mgb-20 multiple-select"
style="width: 300px" style="width: 300px"
value-key="key" value-key="key"
@remove-tag="delSetting"
filterable filterable
@remove-tag="delSetting"
> >
<el-tooltip <el-tooltip
v-for="item in settingsList"
:key="item.key"
class="item" class="item"
:content="item.comment" :content="item.comment"
placement="left" placement="left"
v-for="item in settingsList"
:key="item.key"
:disabled="!item.comment" :disabled="!item.comment"
> >
<el-option <el-option
@ -159,17 +159,17 @@
</el-select> </el-select>
<div class="btn-group"> <div class="btn-group">
<el-button <el-button
v-if="permSettings"
type="success" type="success"
size="small" size="small"
@click="addSetting" @click="addSetting"
v-if="permSettings"
>添加新的配置项</el-button> >添加新的配置项</el-button>
<el-button <el-button
v-show="selectedSettings.length > 0" v-show="selectedSettings.length > 0"
v-if="permEdit"
type="danger" type="danger"
size="small" size="small"
@click="clearSettings" @click="clearSettings"
v-if="permEdit"
>清空</el-button> >清空</el-button>
<el-button <el-button
size="small" size="small"
@ -218,13 +218,13 @@
label="名称" label="名称"
prop="value.title" prop="value.title"
> >
<el-input v-model="newSettingForm.value.title" /> <el-input v-model="newSettingForm.value.title"/>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="key" label="key"
prop="key" prop="key"
> >
<el-input v-model="newSettingForm.key" /> <el-input v-model="newSettingForm.key"/>
<span class="ipt-tip">该值写入redis并传入客户端请谨慎填写</span> <span class="ipt-tip">该值写入redis并传入客户端请谨慎填写</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -255,15 +255,15 @@
label="是否禁用" label="是否禁用"
prop="disabled" prop="disabled"
> >
<el-switch v-model="newSettingForm.disabled"></el-switch> <el-switch v-model="newSettingForm.disabled"/>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="说明" label="说明"
prop="comment" prop="comment"
> >
<el-input <el-input
type="textarea"
v-model="newSettingForm.comment" v-model="newSettingForm.comment"
type="textarea"
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -280,9 +280,9 @@
<script> <script>
import vueJsonEditor from 'vue-json-editor' import vueJsonEditor from 'vue-json-editor'
import {Promise} from 'q' import { Promise } from 'q'
import {mapGetters} from 'vuex' import { mapGetters } from 'vuex'
import {getGame} from '@/api/games' import { getGame } from '@/api/games'
import { import {
resetSettings, resetSettings,
getGameSettings, getGameSettings,
@ -343,12 +343,12 @@ export default {
comment: '', comment: '',
}, },
newSettingRules: { newSettingRules: {
key: [{required: true, message: '请输入 key 值', trigger: 'blur'}], key: [{ required: true, message: '请输入 key 值', trigger: 'blur' }],
'value.title': [ 'value.title': [
{required: true, message: '请填写名称', trigger: 'blur'}, { required: true, message: '请填写名称', trigger: 'blur' },
], ],
'value.type': [ 'value.type': [
{required: true, message: '请选择值类型', trigger: 'blur'}, { required: true, message: '请选择值类型', trigger: 'blur' },
], ],
}, },
} }
@ -388,9 +388,9 @@ export default {
}, },
// left // left
getGameInfo(cb) { getGameInfo(cb) {
getGame({uid: this.uid}) getGame({ uid: this.uid })
.then(res => { .then(res => {
const {data} = res const { data } = res
if (data.errcode === 0) { if (data.errcode === 0) {
this.gameInfo = data.gameInfo this.gameInfo = data.gameInfo
this.platformsArr = data.gameInfo.platforms this.platformsArr = data.gameInfo.platforms
@ -418,7 +418,7 @@ export default {
id: this.gameInfo.game_id, id: this.gameInfo.game_id,
pid: this.platform_id, pid: this.platform_id,
}).then(res => { }).then(res => {
const {data} = res const { data } = res
if (data.errcode !== 0) { if (data.errcode !== 0) {
this.$notify.error({ this.$notify.error({
title: '错误', title: '错误',
@ -513,7 +513,7 @@ export default {
pid: this.platform_id, pid: this.platform_id,
}) })
.then(res => { .then(res => {
const {data} = res const { data } = res
if (data.errcode === 0) { if (data.errcode === 0) {
this.settingsForm.settings = data.records this.settingsForm.settings = data.records
this.selectedSettings = data.records this.selectedSettings = data.records
@ -558,7 +558,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}) })
.then(async () => { .then(async() => {
// //
this.saveSettings() this.saveSettings()
.then(() => { .then(() => {
@ -569,7 +569,7 @@ export default {
platform: this.platform_id, platform: this.platform_id,
type: this.settingType, type: this.settingType,
}).then(res => { }).then(res => {
const {data} = res const { data } = res
if (data.errcode !== 0) { if (data.errcode !== 0) {
this.$notify.error({ this.$notify.error({
title: '错误', title: '错误',
@ -604,7 +604,7 @@ export default {
platform: this.platform_id, platform: this.platform_id,
type: this.settingType, type: this.settingType,
}).then(res => { }).then(res => {
const {data} = res const { data } = res
if (data.errcode !== 0) { if (data.errcode !== 0) {
this.$notify.error({ this.$notify.error({
title: '错误', title: '错误',
@ -628,7 +628,7 @@ export default {
// right // right
getSettingsList() { getSettingsList() {
getSettingItems().then(res => { getSettingItems().then(res => {
const {data} = res const { data } = res
if (data.errcode !== 0) { if (data.errcode !== 0) {
this.$notify.error({ this.$notify.error({
title: '错误', title: '错误',
@ -735,7 +735,7 @@ export default {
comment: this.newSettingForm.comment, comment: this.newSettingForm.comment,
}, },
}).then(res => { }).then(res => {
const {data} = res const { data } = res
if (data.errcode !== 0) { if (data.errcode !== 0) {
this.$message.error(data.errmsg) this.$message.error(data.errmsg)
return return

View File

@ -0,0 +1,380 @@
<template>
<div class="main-content">
<el-form
ref="mainForm"
:rules="mainFormRules"
label-width="120px"
style="width: 60%"
>
<el-form-item label="平台">
<el-select
v-model="platform_id"
style="width: 70%"
@change="changePlatform"
>
<el-option
v-for="item in platformsArr"
:key="item.platform.platform_id"
:label="item.platform.name"
:value="item.platform.platform_id"
/>
</el-select>
</el-form-item>
<el-form-item
label="启动参数白名单"
prop="name"
>
<el-input v-model="whiteTxt"/>
</el-form-item>
<el-form-item
label="地区"
>
<tree-transfer
:title="areaOptions.areaTitles"
:from_data="areaFrom"
:to_data="areaSelected"
:default-props="{label:'name'}"
mode="transfer"
height="540px"
filter
:open-all="areaOptions.openAll"
high-light
@addBtn="addArea"
@removeBtn="removeArea"
/>
</el-form-item>
<el-form-item
label="屏蔽时间段"
prop="share_word"
>
<el-row
v-for="(item, index) in timeGroups"
:key="index"
class="share-group"
type="flex"
align="middle"
:gutter="16"
>
<el-col :span="8">
<div class="txt ell">{{ item.start }}</div>
</el-col>
<el-col :span="8">
<div class="txt ell">{{ item.end }}</div>
</el-col>
<el-col :span="16">
<el-button
type="primary"
size="mini"
@click="editTimeGroup(item, index)"
>编辑</el-button>
<el-button
type="danger"
size="mini"
@click="delTimeGroup(index)"
>删除</el-button>
</el-col>
</el-row>
<el-button
v-if="permEdit"
size="mini"
@click="addTimeGroup"
>添加时间段</el-button>
</el-form-item>
<el-form-item>
<el-button
v-if="permEdit"
type="primary"
@click="save"
>保存</el-button>
</el-form-item>
</el-form>
<!-- Modal - 编辑时间段 -->
<el-dialog
title="修改时间"
:visible.sync="modalEditTimeVisible"
width="35%"
>
<el-form
ref="timeForm"
:model="timeForm"
:rules="timeFormRules"
>
<el-form-item
label="起始时间"
prop="start"
>
<el-time-select
v-model="timeForm.start"
placeholder="起始时间"
:picker-options="{
start: '00:00',
step: '00:15',
end: '24:00'
}"
/>
</el-form-item>
<el-form-item
label="结束时间"
prop="end"
>
<el-time-select
v-model="timeForm.end"
placeholder="结束时间"
:picker-options="{
start: '00:00',
step: '00:15',
end: '24:00',
minTime: timeForm.start
}"
/>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="closeModalTimeEdit"> </el-button>
<el-button
v-if="permEdit"
type="primary"
@click="saveTime"
> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getRegionWithId } from '@/api/common'
import treeTransfer from 'el-tree-transfer'
import { getGame, getIpInfo, saveIpInfo } from '@/api/games'
import { mapGetters } from 'vuex'
export default {
name: 'GameDetailsIP',
components: {
treeTransfer,
},
data() {
return {
// common
uid: '',
gid: '',
permEdit: false,
platform_id: 'all',
areas: [],
areaFrom: [],
whiteTxt: '',
areaSelected: [],
timeGroups: [],
areaOptions: {
openAll: false,
areaTitles: ['可选地区', '已选地区'],
},
platformsArr: [{ platform: { platform_id: 'all', name: '所有平台' }}],
mainForm: {
},
mainFormRules: {
},
timeForm: {
},
timeFormRules: {
start: [{ required: true, message: '请选择开始时间', trigger: 'blur' }],
end: [{ required: true, message: '请选择结束时间', trigger: 'blur' }]
},
modalEditTimeVisible: false,
}
},
computed: {
...mapGetters(['userInfo']),
},
async mounted() {
this.uid = this.$route.params.uid
this.permEdit =
this.userInfo.permissions.includes(`${this.uid}-edit`) ||
this.userInfo.permissions.includes(`games-writeable`)
await this.fetchGameInfo()
await this.fetchRegins()
if (this.gid) {
await this.fetchIpInfo(this.gid, this.platform_id)
}
this.rebuildAreaData()
},
methods: {
save() {
this.updateIpInfo()
},
async reset() {
try {
await this.$confirm('确定忽略任何修改?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
this.$refs['mainForm'].resetFields()
} catch (err) {
console.log('cancel clicked')
}
},
async changePlatform() {
if (!this.gid) {
this.$message.error('无法获取游戏基本信息')
return
}
await this.fetchIpInfo(this.gid, this.platform_id)
this.rebuildAreaData()
},
addArea(fromData, toData, obj) {
console.log('fromData:', fromData)
console.log('toData:', toData)
console.log('obj:', obj)
this.areaFrom = fromData
this.areaSelected = toData
const map = new Map(this.areaFrom.map(i => [i.id, i]))
for (const area of this.areaSelected) {
area.all = !map.has(area.id)
}
},
removeArea(fromData, toData, obj) {
console.log('fromData:', fromData)
console.log('toData:', toData)
console.log('obj:', obj)
this.areaFrom = fromData
this.areaSelected = toData
const map = new Map(this.areaFrom.map(i => [i.id, i]))
for (const area of this.areaSelected) {
area.all = !map.has(area.id)
}
},
addTimeGroup() {
this.timeForm = {}
this.openModalTimeEdit()
},
editTimeGroup(item, index) {
this.timeForm = this.timeGroups[index]
this.openModalTimeEdit()
},
async delTimeGroup(index) {
try {
await this.$confirm('确定删除该时间段?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
this.timeGroups.splice(index, 1)
} catch (err) {
console.log('cancel clicked')
}
},
openModalTimeEdit() {
this.modalEditTimeVisible = true
},
closeModalTimeEdit() {
this.$refs['timeForm'].clearValidate()
this.modalEditTimeVisible = false
},
saveTime() {
console.log(this.timeForm)
if (!this.timeForm.idx) {
let maxIdx = 0
for (const obj of this.timeGroups) {
maxIdx = Math.max(maxIdx, obj.idx)
}
this.timeForm.idx = maxIdx + 1
this.timeGroups.push(this.timeForm)
}
this.closeModalTimeEdit()
},
async fetchRegins() {
try {
const res = await getRegionWithId()
const data = res.data
if (data['errcode'] === 0) {
this.areas = data.records
} else {
this.$message.error(`服务器返回errcode: ${data['errcode']}, msg: ${data['errmsg']}`)
}
} catch (err) {
console.error(err)
this.$message.error('获取地区基本信息出错')
}
},
async fetchGameInfo() {
try {
const res = await getGame({ uid: this.uid })
const { data } = res
if (data['errcode'] === 0) {
this.platformsArr.push(...data.gameInfo.platforms)
this.gid = data.gameInfo.game_id
} else {
this.$message.error(`服务器返回errcode: ${data['errcode']}, msg: ${data['errmsg']}`)
}
} catch (err) {
console.log(err)
this.$message.error('获取游戏基本信息出错')
}
},
async fetchIpInfo(gid, pid) {
try {
const res = await getIpInfo(gid, pid)
const { data } = res
if (data['errcode'] === 0) {
const ipdata = data.data || {}
this.whiteTxt = ipdata['more_params'] || ''
this.timeGroups = ipdata.times || []
this.areaSelected = ipdata.areas || []
} else {
this.$message.error(`服务器返回errcode: ${data['errcode']}, msg: ${data['errmsg']}`)
}
} catch (err) {
console.log(err)
this.$message.error('获取配置信息出错')
}
},
async updateIpInfo() {
try {
const dataSave = {
game_id: this.gid,
platform_id: this.platform_id,
more_params: this.whiteTxt,
times: this.timeGroups,
areas: this.areaSelected
}
const res = await saveIpInfo({ data: dataSave })
const { data } = res
if (data['errcode'] === 0) {
console.log('success')
this.$message({
message: '保存成功',
type: 'success'
})
} else {
this.$message.error(`服务器返回errcode: ${data['errcode']}, msg: ${data['errmsg']}`)
}
} catch (err) {
console.error(err)
this.$message.error('保存出错')
}
},
rebuildAreaData() {
const arr = []
const map = new Map(this.areaSelected.map(i => [i.id, i]))
for (const area of this.areas) {
if (map.has(area.id)) {
const subMap = new Map(map.get(area.id).children.map(i => [i.id, i]))
const subArr = []
for (const sub of area.children) {
if (!subMap.has(sub.id)) {
subArr.push(sub)
}
}
if (subArr.length > 0) {
area.children = subArr
arr.push(area)
}
} else {
arr.push(area)
}
}
this.areaFrom = arr
}
}
}
</script>