|
|
|
<script setup>
|
|
|
|
import {ref, reactive, onBeforeMount, onMounted, onUnmounted, watch, watchEffect} from "vue";
|
|
|
|
import Sortable from "sortablejs";
|
|
|
|
import {useStore, mapState} from "vuex";
|
|
|
|
import JsonEditorVue from "json-editor-vue3";
|
|
|
|
import {ec_api_send_request, get_ec_api_request_url} from "@/apis/ec_api.js";
|
|
|
|
import {Refresh} from "@element-plus/icons-vue";
|
|
|
|
import "@/VueAceEditor/aceConfig"
|
|
|
|
import { VAceEditor } from "vue3-ace-editor";
|
|
|
|
import {ElMessage} from "element-plus";
|
|
|
|
|
|
|
|
|
|
|
|
// 注册store
|
|
|
|
const store = useStore()
|
|
|
|
|
|
|
|
// 标签相关的定义
|
|
|
|
const tabsRef = ref(null); // tabs的Ref
|
|
|
|
const activeTab = ref(store.state.ecApiModule.first_tab_api_id); // 当前选项卡,存储的是api_id
|
|
|
|
|
|
|
|
|
|
|
|
// 表格相关的定义
|
|
|
|
const ApiTableRef = ref(null) // 表格的Ref
|
|
|
|
// const multipleSelection = ref([]) // checkbox的处理
|
|
|
|
|
|
|
|
// 定义变量用于存储接口设置的数据
|
|
|
|
const UserApiData = ref({api: {}, base_info: {}, tab: {}})
|
|
|
|
|
|
|
|
// 表格逻辑
|
|
|
|
// 多选改变后处理逻辑
|
|
|
|
function handleParamsChange(newCheckedResult) {
|
|
|
|
// console.log('handleParamsChange', newCheckedResult)
|
|
|
|
// console.log('activeTab.value', activeTab.value)
|
|
|
|
// console.log('UserApiData.value.api[activeTab.value]', UserApiData.value.api[activeTab.value])
|
|
|
|
}
|
|
|
|
|
|
|
|
// 遍历当前标签页下的参数如果勾选则标记is_checked为true
|
|
|
|
function handleParamsSelect(val) {
|
|
|
|
UserApiData.value.api[activeTab.value].params.forEach(param => {
|
|
|
|
param['is_checked'] = val.indexOf(param) >= 0;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 自动勾选行 切换标签后检查全部字段,如果字段的is_checked是true则在页面上勾选字段
|
|
|
|
function markIsChecked() {
|
|
|
|
if (UserApiData.value.hasOwnProperty('api') || UserApiData.value.api.length > 0) {
|
|
|
|
UserApiData.value.api[activeTab.value].params.forEach(item => {
|
|
|
|
if (item['is_checked'] === true) {
|
|
|
|
ApiTableRef.value[UserApiData.value.tab[activeTab.value]].toggleRowSelection(item, true)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 过滤生成url的必须参数,必须包含'format', 'pid', '_sig'否则后端会报错
|
|
|
|
function checkboxFilter(row) {
|
|
|
|
const special_params = ['format', 'pid', '_sig']
|
|
|
|
return special_params.indexOf(row.param) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 初始逻辑数据逻辑处理
|
|
|
|
function initApiData() {
|
|
|
|
// 更新基础数据
|
|
|
|
UserApiData.value['base_info'] = {
|
|
|
|
env: store.state.ecApiModule.ec_api_data.env,
|
|
|
|
cinema: store.state.ecApiModule.ec_api_data.cinema,
|
|
|
|
channel: store.state.ecApiModule.ec_api_data.channel,
|
|
|
|
}
|
|
|
|
// 根据store.state.ecApiModule.ec_api_data.api来创建本都数据
|
|
|
|
let api_id_array = []
|
|
|
|
let api_tab = {}
|
|
|
|
if (store.state.ecApiModule.ec_api_data.api) {
|
|
|
|
store.state.ecApiModule.ec_api_data.api.forEach((item, index) => {
|
|
|
|
api_id_array.push(item.id)
|
|
|
|
api_tab[item.id] = index
|
|
|
|
if (!UserApiData.value['api'].hasOwnProperty(item.id)) {
|
|
|
|
UserApiData.value['api'][item.id] = {
|
|
|
|
'id': item.id,
|
|
|
|
'description': item.description,
|
|
|
|
'path': item.path,
|
|
|
|
'type': item.type,
|
|
|
|
'url': '',
|
|
|
|
'response': '{"root": "root"}',
|
|
|
|
'sig': '',
|
|
|
|
'format': 'json',
|
|
|
|
'params': store.state.ecApiModule.ec_api_data.api_params[item.id]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
// 如果删除某接口后同步删除UserApiData中的数据
|
|
|
|
Object.values(UserApiData.value['api']).forEach((api) => {
|
|
|
|
if (api_id_array.indexOf(api['id']) < 0) {
|
|
|
|
delete UserApiData.value['api'][api['id']]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
// 处理cid和pid
|
|
|
|
Object.keys(UserApiData.value['api']).forEach(api_id => {
|
|
|
|
UserApiData.value['api'][api_id]['params'].forEach(
|
|
|
|
param_item => {
|
|
|
|
if (param_item['param'] === 'cid') {
|
|
|
|
param_item['value'] = UserApiData.value['base_info']['cinema']
|
|
|
|
}
|
|
|
|
if (param_item['param'] === 'pid') {
|
|
|
|
param_item['value'] = UserApiData.value['base_info']['channel']
|
|
|
|
}
|
|
|
|
// 写入默认值
|
|
|
|
param_item['default'] = param_item['value']
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
// 把生成的接口数据赋给UserApiData
|
|
|
|
UserApiData.value.tab = api_tab
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加新字段
|
|
|
|
function addNewParams() {
|
|
|
|
UserApiData.value.api[activeTab.value].params.push({
|
|
|
|
id: Date.now(),
|
|
|
|
api_id: activeTab.value,
|
|
|
|
param: '',
|
|
|
|
value: '',
|
|
|
|
is_request: false,
|
|
|
|
is_checked: false,
|
|
|
|
is_preset: false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 读取参数默认值
|
|
|
|
function loadDefault(param) {
|
|
|
|
console.log(param)
|
|
|
|
UserApiData.value.api[activeTab.value]['params'].forEach(p => {
|
|
|
|
if (p['param'] === param) {
|
|
|
|
p['value'] = p['default']
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 切换返回数据格式
|
|
|
|
function changeFormat() {
|
|
|
|
UserApiData.value.api[activeTab.value]['params'].forEach(p => {
|
|
|
|
if (p['param'] === 'format') {
|
|
|
|
if (['json', 'xml'].indexOf(p['value']) < 0) {
|
|
|
|
alert('format参数值支持json和xml')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (p['value'] === 'json') {
|
|
|
|
UserApiData.value.api[activeTab.value]['format'] = 'json'
|
|
|
|
p['response'] = '{"root": "root"}'
|
|
|
|
}
|
|
|
|
if (p['value'] === 'xml') {
|
|
|
|
UserApiData.value.api[activeTab.value]['format'] = 'html'
|
|
|
|
UserApiData.value.api[activeTab.value]['response'] = '<root></root>'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 准备获取url和发送请求需要的参数
|
|
|
|
function handle_request_data() {
|
|
|
|
let data = {}
|
|
|
|
let req_data = {}
|
|
|
|
UserApiData.value.api[activeTab.value]['params'].forEach(
|
|
|
|
p => {
|
|
|
|
if (p['param'] !== '_sig' && p['is_checked'] === true) {
|
|
|
|
req_data[p['param']] = p['value']
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
data['env'] = UserApiData.value.base_info['env']
|
|
|
|
data['type'] = UserApiData.value.api[activeTab.value]['type']
|
|
|
|
data['api'] = UserApiData.value.api[activeTab.value]['path']
|
|
|
|
data['params'] = JSON.stringify(req_data)
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
|
|
|
|
// 生成请求的url,用于页面展示
|
|
|
|
function handle_request_url() {
|
|
|
|
console.log('UserApiData.value', UserApiData.value)
|
|
|
|
if (UserApiData.value.base_info['cinema'] === '' || UserApiData.value.base_info['channel'] === '') {
|
|
|
|
alert('请选择影院和渠道!')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const data = handle_request_data()
|
|
|
|
get_ec_api_request_url(data).then(res => {
|
|
|
|
console.log('handle_update_url', res)
|
|
|
|
UserApiData.value.api[activeTab.value]['url'] = res['url']
|
|
|
|
UserApiData.value.api[activeTab.value]['params'].forEach(p => {
|
|
|
|
if (p['param'] === '_sig') {
|
|
|
|
p['value'] = res['sig']
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}).catch(err => console.log(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
// 发送api请求
|
|
|
|
function send_request() {
|
|
|
|
if (UserApiData.value.api[activeTab.value].format === 'json'){
|
|
|
|
UserApiData.value.api[activeTab.value].response = '{"root": "root"}'
|
|
|
|
}
|
|
|
|
if (UserApiData.value.api[activeTab.value].format === 'html' || UserApiData.value.api[activeTab.value].format === 'xml'){
|
|
|
|
UserApiData.value.api[activeTab.value].response = '<root></root>'
|
|
|
|
}
|
|
|
|
const data = handle_request_data()
|
|
|
|
ec_api_send_request(data).then(res => {
|
|
|
|
if (res.format === 'json') {
|
|
|
|
UserApiData.value.api[activeTab.value].response = JSON.stringify(JSON.parse(res.data), null, 2)
|
|
|
|
}
|
|
|
|
if (res.format === 'xml') {
|
|
|
|
const xmlDoc = new DOMParser().parseFromString(res.data , 'application/xml');
|
|
|
|
const serializer = new XMLSerializer();
|
|
|
|
UserApiData.value.api[activeTab.value].response = serializer.serializeToString(xmlDoc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 用于测试,可以添加到需要的方法中
|
|
|
|
function test() {
|
|
|
|
console.log('store.state.ecApiModule.ec_api_data', store.state.ecApiModule.ec_api_data)
|
|
|
|
console.log('UserApiData.value', UserApiData.value)
|
|
|
|
// console.log('activeTab.value', activeTab.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 监测ec_select_api的变化 生成新的本地数据,如果当前选中的标签被取消勾选,则选择剩下标签的第一个
|
|
|
|
watch(() => store.state.ecApiModule.ec_api_data.api, (oldValue, newValue) => {
|
|
|
|
console.log('watch store.state.ecApiModule.ec_api_data.api')
|
|
|
|
// 接口数据变化后初始化本地数据
|
|
|
|
initApiData()
|
|
|
|
// 处理空标签逻辑
|
|
|
|
const select_api_id = store.getters['ecApiModule/ec_select_api_getter']
|
|
|
|
if (select_api_id.indexOf(activeTab.value) < 0) {
|
|
|
|
activeTab.value = select_api_id[0]
|
|
|
|
}
|
|
|
|
}, {deep: true})
|
|
|
|
|
|
|
|
// 监测activeTab, 如果切换标签页,则执行自动勾选的函数
|
|
|
|
watch(activeTab, () => {
|
|
|
|
markIsChecked()
|
|
|
|
handle_request_url()
|
|
|
|
})
|
|
|
|
|
|
|
|
// 监视本地用户数据,如果数据改变,则更新url
|
|
|
|
watch(UserApiData.value, () => {
|
|
|
|
console.log('watch UserApiData', UserApiData.value)
|
|
|
|
handle_request_url()
|
|
|
|
}, {deep: true, flush: "post"})
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
生命周期逻辑
|
|
|
|
*/
|
|
|
|
onBeforeMount(
|
|
|
|
() => {
|
|
|
|
// console.log('TabArea onBeforeMount')
|
|
|
|
// 处理请求参数生成本地数据结构
|
|
|
|
initApiData()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// 挂载后
|
|
|
|
onMounted(() => {
|
|
|
|
// console.log('TabArea onMounted')
|
|
|
|
// 勾选is_checked选项
|
|
|
|
markIsChecked()
|
|
|
|
// 处理拖拽
|
|
|
|
const elTabsHeader = tabsRef.value.$el.querySelector('.el-tabs__header .el-tabs__nav');
|
|
|
|
const sortTabs = new Sortable(elTabsHeader, {
|
|
|
|
animation: 150,
|
|
|
|
ghostClass: 'dragging',
|
|
|
|
draggable: '.el-tabs__item',
|
|
|
|
onEnd: (evt) => {
|
|
|
|
store.commit('ecApiModule/handle_sort_ec_select_api', {'newIndex': evt.newIndex, 'oldIndex': evt.oldIndex})
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// 设置vue3-ace-editor
|
|
|
|
const ace_options = {
|
|
|
|
useWorker: false, // 启用语法检查,必须为true
|
|
|
|
enableBasicAutocompletion: false, // 自动补全
|
|
|
|
enableLiveAutocompletion: false, // 智能补全
|
|
|
|
enableSnippets: true, // 启用代码段
|
|
|
|
showPrintMargin: false, // 去掉灰色的线,printMarginColumn
|
|
|
|
highlightActiveLine: true, // 高亮行
|
|
|
|
highlightSelectedWord: true, // 高亮选中的字符
|
|
|
|
tabSize: 4, // tab锁进字符
|
|
|
|
fontSize: 14, // 设置字号
|
|
|
|
wrap: false, // 是否换行
|
|
|
|
readonly: true, // 是否可编辑
|
|
|
|
minLines: 30, // 最小行数,minLines和maxLines同时设置之后,可以不用给editor再设置高度
|
|
|
|
maxLines: 30, // 最大行数
|
|
|
|
}
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
|
|
<el-tabs ref="tabsRef" v-model="activeTab" type="border-card">
|
|
|
|
<el-tab-pane
|
|
|
|
v-for="(api, index) in store.state.ecApiModule.ec_api_data.api"
|
|
|
|
:key="api['id']"
|
|
|
|
:label="api['description']"
|
|
|
|
:name="api['id']"
|
|
|
|
>
|
|
|
|
<el-table
|
|
|
|
ref='ApiTableRef'
|
|
|
|
:data="UserApiData.api[api['id']].params"
|
|
|
|
@selection-change="handleParamsChange"
|
|
|
|
@select="handleParamsSelect"
|
|
|
|
>
|
|
|
|
<el-table-column type="selection" width="50" :selectable="checkboxFilter"/>
|
|
|
|
<el-table-column label="字段名" width="200">
|
|
|
|
<template v-slot="scope">
|
|
|
|
<span v-if="scope.row.is_preset">{{ scope.row.param }}</span>
|
|
|
|
<span v-else><el-input type="text" placeholder="输入字段名" v-model="scope.row.param"></el-input></span>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="字段值" width="800">
|
|
|
|
<template v-slot="scope">
|
|
|
|
<el-input type="textarea" placeholder="输入字段值" v-model="scope.row.value" rows="1"
|
|
|
|
@blur="changeFormat()"></el-input>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="重置" width="80">
|
|
|
|
<template v-slot="scope">
|
|
|
|
<el-button @click="loadDefault(scope.row.param)">
|
|
|
|
<el-icon>
|
|
|
|
<Refresh/>
|
|
|
|
</el-icon>
|
|
|
|
</el-button>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="必选" width="80">
|
|
|
|
<template v-slot="scope">
|
|
|
|
<span>{{ scope.row.is_request ? '是' : '否' }}</span>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="description" label="描述" show-overflow-tooltip/>
|
|
|
|
</el-table>
|
|
|
|
<el-row class="BtnRow" style="width: 100%">
|
|
|
|
<el-col :span="2">
|
|
|
|
<el-button type="primary" @click="addNewParams">添加新字段</el-button>
|
|
|
|
</el-col>
|
|
|
|
</el-row>
|
|
|
|
<hr id="break_line"/>
|
|
|
|
<el-row class="BtnRow" style="width: 100%" :gutter="10" align="middle">
|
|
|
|
<el-col :span="2"><span style="font-weight: bold; color: #909399">请求地址:</span></el-col>
|
|
|
|
<el-col :span="12">
|
|
|
|
<el-input type="text" v-model="UserApiData.api[api['id']].url" :style="{'font-size': '18px'}"></el-input>
|
|
|
|
</el-col>
|
|
|
|
<el-col :span="2">
|
|
|
|
<el-button type="primary" @click="send_request">发送</el-button>
|
|
|
|
</el-col>
|
|
|
|
<el-col :span="8">
|
|
|
|
</el-col>
|
|
|
|
</el-row>
|
|
|
|
<v-ace-editor v-model:value="UserApiData.api[api['id']].response" :lang="UserApiData.api[api['id']]['format']"
|
|
|
|
theme="chrome" :options="ace_options" class="vue-ace-editor" :wrap="true" style="width: 1200px"/>
|
|
|
|
</el-tab-pane>
|
|
|
|
</el-tabs>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.BtnRow {
|
|
|
|
margin-top: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.editor {
|
|
|
|
margin-top: 20px;
|
|
|
|
margin-bottom: 20px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.vue-ace-editor {
|
|
|
|
/* ace-editor默认没有高度,所以必须设置高度,或者同时设置最小行和最大行使编辑器的高度自动增高 */
|
|
|
|
margin-top: 20px;
|
|
|
|
margin-left: 20px;
|
|
|
|
border: 1px solid rgba(144, 147, 153, 0.5);
|
|
|
|
border-radius: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
#break_line {
|
|
|
|
margin-top: 30px;
|
|
|
|
margin-bottom: 30px;
|
|
|
|
background-color: rgba(144, 147, 153, 0.5);
|
|
|
|
height: 1px;
|
|
|
|
border: none
|
|
|
|
}
|
|
|
|
</style>
|