Commit 629b91e0 authored by 徐光星's avatar 徐光星

Merge branch 'feat/v1.5-backup' into 'master'

Feat/v1.5 backup

See merge request !68
parents c50c239a 67761a47
......@@ -17,7 +17,8 @@ export default class EditorController extends Controller {
try {
const result = await ctx.model.PageInfo.create({ ...pageInfo, uuid: uuidv1().replace(/-/g, ''), tenantId: ctx.headers['qg-tenant-id']});
ctx.body = ctx.helper.ok(result);
await ctx.service.redis.set(`pageInfo:${result.dataValues.uuid}`, result.dataValues);
await ctx.service.redis.del(`pageInfo:${result.dataValues.uuid}`);
await ctx.service.redis.del(`page:${result.dataValues.uuid}`);
} catch (error) {
if (error.message.indexOf('Data too long') > -1 && error.message.indexOf('page_data') > -1) {
error.message = '配置组件过多,请对组件进行删减';
......@@ -36,9 +37,9 @@ export default class EditorController extends Controller {
}
try {
const result = await ctx.model.PageInfo.update(pageInfo, {where: { uuid: pageInfo.uuid, tenantId: ctx.headers['qg-tenant-id'] }});
await ctx.service.redis.set(`pageInfo:${pageInfo.uuid}`, pageInfo);
await ctx.service.redis.del(`pageInfo:${pageInfo.uuid}`);
await ctx.service.redis.del(`page:${pageInfo.uuid}`);
ctx.body = ctx.helper.ok(result);
ctx.body = ctx.helper.ok(result);
} catch (error) {
if (error.message.indexOf('Data too long') > -1 && error.message.indexOf('page_data') > -1) {
error.message = '配置组件过多,请对组件进行删减';
......@@ -48,11 +49,12 @@ export default class EditorController extends Controller {
}
// todo 编辑器获取跳过redis,但需要注意
public async get(ctx: Context) {
let pageInfo = await ctx.service.redis.get(`pageInfo:${ctx.params.uuid}`);
const { isEditor } = ctx.query;
let pageInfo = isEditor ? null : await ctx.service.redis.get(`pageInfo:${ctx.params.uuid}`);
console.log('redis', pageInfo);
if (!pageInfo) {
let pageInfo = await ctx.model.PageInfo.findOne({where: { uuid: ctx.params.uuid }});
console.log('sql', pageInfo);
pageInfo = await ctx.model.PageInfo.findOne({where: { uuid: ctx.params.uuid }});
console.log('sql', pageInfo);
if (ctx.query.lite && pageInfo) {
// 如果存在sheme移除掉
......@@ -102,7 +104,7 @@ export default class EditorController extends Controller {
const where = {
updated_at: {
[ctx.model.Sequelize.Op.lt]: Date.now(),
[ctx.model.Sequelize.Op.gt]: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7)
[ctx.model.Sequelize.Op.gt]: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30)
},
tenantId: ctx.headers['qg-tenant-id'],
enable: 1,
......@@ -114,6 +116,7 @@ export default class EditorController extends Controller {
});
for (const item of pageInfo) {
await ctx.service.redis.del(`page:${item.uuid}`);
await ctx.service.redis.del(`pageInfo:${item.uuid}`);
ctx.logger.info(`del redis page key page:${item.uuid}`);
}
ctx.body = ctx.helper.ok();
......
import { Controller, Context } from 'egg';
export default class NavigatorController extends Controller {
public async getNavigatorConfigList(ctx: Context) {
// 查询导航配置列表
const { pageNo, pageSize, name, author} = ctx.query;
try {
const list = await ctx.service.navigator.getList(pageNo, pageSize, name, author);
ctx.body = ctx.helper.ok(list);
} catch (e) {
ctx.logger.info(`获取导航配置数据异常, ${JSON.stringify(e)}`);
ctx.body = ctx.helper.fail({
message: '获取数据异常'
});
}
}
// 查询导航配置列表(父子接口,供选择页面使用,且带有分页)
public async getNavigatorConfigListWithRelation(ctx: Context) {
const { pageNo, pageSize, name, author, id } = ctx.query;
try {
const list = await ctx.service.navigator.getNavigatorConfigListWithRelation(pageNo, pageSize, name, author, id);
ctx.body = ctx.helper.ok(list);
} catch (e) {
ctx.logger.info(`获取导航配置数据异常, ${JSON.stringify(e)}`);
ctx.body = ctx.helper.fail({
message: '获取数据异常'
});
}
}
// 删除导航配置
public async deleteNavigatorConfig(ctx: Context) {
const { id } = ctx.request.body;
try {
await ctx.service.navigator.deleteById(id);
ctx.body = ctx.helper.ok({});
} catch (e) {
ctx.logger.info(`删除导航配置异常, ${JSON.stringify(e)}`);
ctx.body = ctx.helper.fail({
message: '删除导航配置失败'
});
}
}
// 保存导航配置
public async saveNavigatorConfig(ctx: Context) {
const pageInfo = ctx.request.body;
if (!pageInfo.id) {
delete pageInfo.id;
}
try {
for (let i = 0; i < pageInfo.navigatorData.length; i++) {
let item = pageInfo.navigatorData[i];
if (item.pageType != 1) {
let url = new URL(item.pageUrl);
let pageUUID = url.pathname.replace('/activity/', '');
await ctx.service.redis.del(`page:${pageUUID}`);
await ctx.service.redis.del(`pageInfo:${pageUUID}`);
ctx.logger.info(`del redis page key page:${pageUUID}`);
}
}
await ctx.service.navigator.saveOrUpdate(pageInfo);
ctx.body = ctx.helper.ok({});
} catch (e) {
ctx.logger.info(`保存导航配置异常, ${JSON.stringify(e)}`);
ctx.body = ctx.helper.fail({
message: '保存导航配置失败'
});
}
}
// 获取导航配置详细信息
public async getNavigatorDetail(ctx: Context) {
const { navId } = ctx.query;
try {
const res = await ctx.service.navigator.getDetail(navId);
ctx.body = ctx.helper.ok(res);
} catch (e) {
ctx.logger.info(`查询导航配置异常, ${JSON.stringify(e)}`);
ctx.body = ctx.helper.fail({
message: '查询导航配置失败'
});
}
return
}
}
\ No newline at end of file
/**
* @desc 页面信息表
*/
import { AutoIncrement, Column, DataType, Model, PrimaryKey, Table, AllowNull } from 'sequelize-typescript';
@Table({
modelName: 'navigator_config',
freezeTableName: true
})
// 初始化sql
// create table navigator_config (
// id int(11) primary key auto_increment,
// name varchar(255) not null comment '页面名称',
// author varchar(255) not null comment '作者',
// navigatorData text not null comment '导航配置数据',
// `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
// `updatedAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
// );
export class NavigatorConfig extends Model<NavigatorConfig> {
@PrimaryKey
@AutoIncrement
@Column({
type: DataType.INTEGER(11)
})
id: number;
@Column({
field: 'name',
type: DataType.STRING(255)
})
name: string;
@Column({
field: 'author',
type: DataType.STRING(255)
})
author: string;
@Column({
field: 'bgColor',
type: DataType.STRING(255)
})
bgColor: string;
@Column({
field: 'bgImg',
type: DataType.STRING(255)
})
bgImg: string;
@Column({
field: 'navigatorData',
type: DataType.TEXT,
get() {
const configData = this.getDataValue('navigatorData');
return configData ? JSON.parse(configData) : null
},
set(value) {
this.setDataValue('navigatorData', JSON.stringify(value))
// return JSON.stringify(value);
}
})
navigatorData: string;
@Column({
type: DataType.DATE,
field: 'updatedAt',
get() {
const moment = require('moment');
const updatedAt = this.getDataValue('updatedAt');
return moment(updatedAt).format('YYYY-MM-DD HH:mm:ss');
},
})
updatedAt: string;
}
export default () => NavigatorConfig;
\ No newline at end of file
......@@ -19,5 +19,13 @@ export default (application: Application) => {
router.get('/editor/login', controller.editor.login);
router.get('/editor', controller.editor.home);
router.get('/editor/*', controller.editor.home);
// 导航配置相关
router.post('/navigator/save', controller.navigator.saveNavigatorConfig);
router.get('/navigator/list', controller.navigator.getNavigatorConfigList)
router.get('/navigator/list/relation', controller.navigator.getNavigatorConfigListWithRelation);
router.get('/navigator/detail', controller.navigator.getNavigatorDetail);
router.post('/navigator/delete', controller.navigator.deleteNavigatorConfig)
router.get('/*', controller.editor.home);
};
\ No newline at end of file
import { Context, Service } from 'egg';
// 添加或修改url中的参数
function addOrEditUrlParams (url, paramName, replaceWith) {
if (url.indexOf(paramName) > -1) {
let re = /(' + paramName + '=)([^&]*)/gi;
url = url.replace(re, paramName + '=' + replaceWith);
} else {
let paraStr = paramName + '=' + replaceWith;
let idx = url.indexOf('?');
if (idx < 0) {
url += '?';
} else if (idx >= 0 && idx !== url.length - 1) {
url += '&';
}
url = url + paraStr;
}
return url;
};
function deleteUrlParams(url, ref) {
let str = "";
if (url.indexOf('?') != -1) {
str = url.substr(url.indexOf('?') + 1);
} else {
return url;
}
let arr = [];
let returnurl = "";
let setparam = "";
if (str.indexOf('&') != -1) {
arr = str.split('&');
for (let i in arr) {
if (arr[i].split('=')[0] != ref) {
returnurl = returnurl + arr[i].split('=')[0] + "=" + arr[i].split('=')[1] + "&";
}
}
return url.substr(0, url.indexOf('?')) + "?" + returnurl.substr(0, returnurl.length - 1);
} else {
arr = str.split('=');
if (arr[0] == ref) {
return url.substr(0, url.indexOf('?'));
} else {
return url;
}
}
}
export default class ArticeService extends Service {
private context: Context;
constructor(ctx: Context) {
super(ctx);
this.context = ctx;
}
// 获取导航列表
async getList(pageNo, pageSize, name = '', author = '') {
const offset = (+pageNo - 1) * pageSize;
const condition = {
author: null,
name: null
};
// 模糊匹配作者
if (author) {
condition.author = {
$like: '%' + author + '%'
};
}
if (name) {
condition.name = {
$like: '%' + name + '%'
};
}
if (!condition.author) delete condition.author;
if (!condition.name) delete condition.name;
const res = await this.context.model.NavigatorConfig
.findAndCountAll({
where: condition,
limit: +pageSize,
offset,
order: [
['id', 'DESC']
],
})
const result = {
total: res.count || 0,
data: res.rows || []
}
return result;
}
// 选择页面 导航配置 获取列表
async getNavigatorConfigListWithRelation(pageNo, pageSize, name = '', author = '', id) {
const offset = (+pageNo - 1) * pageSize;;
const condition = {
author: null,
name: null,
id: null
};
if (author) {
condition.author = {
$like: '%' + author + '%'
};
}
if (name) {
condition.name = {
$like: '%' + name + '%'
};
}
if (id) {
condition.id = {
$notIn: [id]
}
}
if (!condition.author) delete condition.author;
if (!condition.name) delete condition.name;
if (!condition.id) delete condition.id;
const res = await this.context.model.NavigatorConfig
.findAndCountAll({
where: condition,
limit: +pageSize,
offset
})
const result = {
total: res.count || 0,
data: res.rows || []
}
return result;
}
// 删除导航配置
async deleteById(id) {
const res = await this.context.model.NavigatorConfig.destroy({
where: {
id
}
})
return res;
}
// 保存或编辑
async saveOrUpdate(data) {
if (data.id) {
// 编辑
const id = data.id;
const saveData = Object.assign({}, data);
const navigatorData = saveData.navigatorData;
for (let i = 0; i < navigatorData.length; i++) {
if(navigatorData[i].pageType == 2) {
let url = navigatorData[i].pageUrl;
if (!navigatorData[i].carryNav) {
url = deleteUrlParams(url, 'navId');
url = deleteUrlParams(url, 'index');
} else {
url = addOrEditUrlParams(url, 'navId', id);
url = addOrEditUrlParams(url, 'index', i);
}
navigatorData[i].pageUrl = url;
}
}
delete saveData.id;
const res = await this.context.model.NavigatorConfig.update(saveData, {
where: {
id
}
})
return res;
}
// 保存
const res = await this.context.model.NavigatorConfig.create(data);
const id = res.dataValues.id;
const navigatorData = JSON.parse(res.dataValues.navigatorData);
// 更新保存数据的链接,pageType为2的要进行更新
for (let i = 0; i < navigatorData.length; i++) {
if(navigatorData[i].pageType == 2 && navigatorData[i].carryNav) {
navigatorData[i].pageUrl += `&navId=${id}&index=${i}`;
}
}
const result = await this.context.model.NavigatorConfig.update({
navigatorData
}, {
where: {
id
}
})
return result;
}
// 查询导航配置信息
async getDetail(id) {
const res = await this.context.model.NavigatorConfig.findOne({
where: {
id
}
})
return res;
}
}
......@@ -10,7 +10,7 @@ export default {
return http.post('editor/clearcache');
},
getPageById(params) {
return http.get(`editor/get/${params.pageId}`);
return http.get(`editor/get/${params.pageId}?isEditor=1`);
},
delPageById(pageId) {
return http.delete(`editor/${pageId}`);
......
// 导航配置api
import http from '../service/http.service';
import config from '../config';
import axios from 'axios';
export default {
getList(params) {
return http.get('navigator/list', { params });
},
getListWithRelation(params) {
return http.get('navigator/list/relation', { params });
},
deleteNavigator(params) {
return http.post('navigator/delete', params);
},
saveNavigator(params) {
return http.post('navigator/save', params);
}
};
\ No newline at end of file
......@@ -62,6 +62,12 @@ export default {
icon: 'ios-compose',
path: 'template',
children: []
},
{
name: '导航配置',
icon: 'ios-compose',
path: 'navigator',
children: []
}]
}
},
......
......@@ -41,6 +41,7 @@ export default class Layout extends Vue {
}
select(name) {
console.log();
this.$router.push({
name
});
......
......@@ -7,6 +7,7 @@
<Menu-item v-if="tenant.workist" name="list">作品列表</Menu-item>
<Menu-item v-if="tenant.draftList" name="my">我的草稿</Menu-item>
<Menu-item v-if="tenant.tmplList" name="template">创意模板</Menu-item>
<Menu-item name="navigator">导航配置</Menu-item>
</Menu>
</i-col>
<i-col :span="21" class="layout-menu-right">
......
......@@ -3,15 +3,15 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'http';
const hostMap = {
apiHost: `http://localhost:7002/`,
// apiHost: `http://192.168.28.199:7001/`,
// apiHost: 'https://quantum-blocks-test1.liangkebang.net/',
h5Host: 'https://quantum-h5-test1.liangkebang.net',
// apiHost: 'https://quantum-blocks-qa.liangkebang.net/',
h5Host: 'https://quantum-h5-qa.liangkebang.net',
qiniuHost: `https://appsync.lkbang.net`,
shenceUrl: `${protocol}//bn.xyqb.com/sa?project=default`,
opapiHost: `https://opapi-test1.liangkebang.net`,
opapiHost: `https://opapi-qa.liangkebang.net`,
qiniuUpHost: `${protocol}//up-z0.qiniup.com`,
// kdspHost: 'https://kdsp-api-test1.liangkebang.net',
talosHost: 'https://talos-test1.liangkebang.net',
kdspHost: 'https://kdsp-api-test1.liangkebang.net',
// kdspHost: 'https://kdsp-api-qa.liangkebang.net',
talosHost: 'https://talos-qa.liangkebang.net',
kdspHost: 'https://kdsp-api-qa.liangkebang.net',
yxmTenantId: 560761,
appIdMap: {
560761: 'wxe16bf9293671506c',
......
// 导航配置列表列名
export const columns = function(pointer) {
return [
{
align: 'center',
title: 'ID',
key: 'id',
width: 80
},
{
align: 'center',
title: '名称',
key: 'name'
},
{
align: 'center',
title: '所选页面',
render: (h, params) => {
const navigatorData = params.row.navigatorData;
let str = '';
try {
for (let i = 0; i < navigatorData.length; i++) {
str += `${i + 1}-${navigatorData[i].pageName}; `;
}
return h('span', str);
} catch (e) {
console.log(e);
}
return h('span', str);
}
},
{
align: 'center',
title: '作者',
key: 'author'
},
{
align: 'center',
title: '更新时间',
key: 'updatedAt'
},
{
align: 'center',
title: '操作',
key: 'updateTime',
render: (h, params) => {
const row = params.row;
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
style: {
marginRight: '5px'
},
on: {
click: () => {
pointer.showAddr(row);
}
}
}, '地址列表'),
// h('Button', {
// props: {
// type: 'primary',
// size: 'small'
// },
// style: {
// marginRight: '5px'
// },
// on: {
// click: () => {
// pointer.preview(row);
// }
// }
// }, '预览'),
h('Button', {
props: {
type: 'primary',
size: 'small'
},
style: {
marginRight: '5px'
},
on: {
click: () => {
pointer.edit(row);
}
}
}, '修改'),
h('Button', {
props: {
type: 'error',
size: 'small'
},
on: {
click: () => {
pointer.delete(row);
}
}
}, '删除'),
]);
},
width: 300
}
];
};
// 地址列表列明
export const urlTableColumns = function(pointer) {
return [
{
align: 'center',
title: '排序',
key: 'id',
width: 80
},
{
align: 'center',
title: '导航名称',
key: 'configName',
width: 120
},
{
align: 'center',
title: '所选页面',
key: 'pageName',
width: 120
},
{
align: 'center',
title: '跳转链接',
key: 'pageUrl'
},
];
};
\ No newline at end of file
......@@ -34,7 +34,8 @@ export default class DynamicForm extends Vue {
@Watch('pageData', { immediate: true })
onPageDataChange(newVal) {
const { pageName, pageDescribe, pageKeywords, coverImage, isPublish, isTemplate, shareCoverImage, shareOpenMethod, diversion } = this.pageInfo;
const { pageName, pageDescribe, pageKeywords, coverImage, isPublish, isTemplate, page } = this.pageInfo;
const { shareOpenMethod, shareCoverImage, diversion } = page.props;
this.formCustom = { pageName, pageDescribe, pageKeywords, coverImage, isPublish: !!isPublish, isTemplate: !!isTemplate, shareCoverImage, shareOpenMethod, diversion };
}
......
......@@ -103,6 +103,25 @@
}
},
BeforeUpload: (up, file) => {
const {type, size} = file;
let limit = 0;
// 来自量子积木v1.5需求中的优化点
if (type === 'image/gif') {
// gif限制5M
limit = 5 * 1024 * 1024;
if (size > limit) {
this.$toast('gif图大小不允许超过5Mb');
return false;
}
} else {
// 其他格式限制800KB
limit = 800 * 1024;
if (size > limit) {
this.$toast('文件大小不允许超过800Kb');
return false;
}
}
// if ()
// var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
this.percent = 0;
},
......
......@@ -158,8 +158,20 @@ export default class DynamicPageForm extends Mixins(ContextMenuMixin) {
formDefault: {}
}
];
// 这块用于让被污染的pageInfo的page.props返回shareOpenMethod
otherProps: object[] = [
{
key: 'shareOpenMethod'
},
{
key: 'diversion'
},
{
key: 'shareCoverImage'
},
];
get propsSchema() {
return [...this.titleSchema, ...this.bottomSchema, ...this.floatSchema];
return [...this.titleSchema, ...this.bottomSchema, ...this.floatSchema, ...this.otherProps];
}
@Watch('cartAndShareBtn', { immediate: true })
......
......@@ -22,6 +22,7 @@
<div v-if="!hideAdd" class="toolBarStyle">
<h3>查询数据</h3>
<div>
<Button type="warning" class="btnStyle" @click="$emit('clearCache')">清除缓存</Button>
<Button type="primary" class="btnStyle" @click="newEvent()">新增</Button>
<slot></slot>
</div>
......
......@@ -3,6 +3,7 @@ import VueRouter from 'vue-router';
import Dashboard from '../view/dashboard/index.vue';
import PageList from '../view/pageList/index.vue';
import MyPage from '../view/myPage/index.vue';
import Navigator from '../view/navigator/index.vue';
import Template from '../view/template/index.vue';
import localStorage from '@/service/localStorage.service';
......@@ -29,6 +30,12 @@ export default function createRouter() {
component: PageList
// component: () => import('../view/pageList/index.vue')
},
{
name: 'navigator',
path: '/navigator',
component: Navigator
// component: () => import('../view/pageList/index.vue')
},
{
name: 'my',
path: '/my',
......
<template>
<div>
<div class="search-bar">
<Form @submit.native.prevent inline ref="searchForm" :model="searchForm" class="inline">
<Form-item label="名称" prop="name">
<Input v-model="searchForm.pageName" class="comWidth" />
</Form-item>
<Form-item label="描述" prop="pageDescribe">
<Input v-model="searchForm.pageDescribe" class="comWidth" />
</Form-item>
<Form-item label="作者" prop="author">
<Input v-model="searchForm.author" class="comWidth" />
</Form-item>
<FormItem class="btnGroupStyle">
<div>
<Button class="btnStyle" @click="reset()">重置</Button>
<Button type="primary" class="btnStyle" @click="filter">查询</Button>
</div>
</FormItem>
</Form>
</div>
<div class="tableGroupStyle">
<Table
:columns="columns"
:data="tableData"
class="tableStyle"
/>
<Page
:total="total"
v-if="total > 0"
show-elevator
show-sizer
class="pageStyle"
:current="searchForm.pageNo"
:pageSize="searchForm.pageSize"
@on-change="changePageNo"
/>
<!-- @on-change="changePageNo"
@on-page-size-change="changePageSize" -->
</div>
</div>
</template>
<script>
import api from '@api/editor.api'
import config from '@/config/index';
export default {
data() {
return {
total: 0,
searchForm: {
pageName: '',
pageDescribe: '',
author: '',
pageSize: 10,
pageNo: 1
},
columns: [
{
align: 'center',
title: '页面名称',
key: 'pageName',
width: 150,
},
{
align: 'center',
title: '描述',
key: 'pageDescribe',
width: 150,
},
{
align: 'center',
title: '作者',
key: 'author',
width: 100
},
{
align: 'center',
title: '封面',
width: 60,
render: (h, params) => {
return h('div', {
style: {
padding: '5px 0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
}, [
h('Img', {
style: {
width: '35px'
},
attrs: {
src: params.row.coverImage
}
})
])
}
},
{
align: 'center',
title: '链接',
render: (h, params) => {
return h('span', `${config.h5Host}/activity/${params.row.uuid}?tenantId=${params.row.tenantId}&vccToken={token}`)
}
},
{
align: 'center',
title: '操作',
width: 80,
render: (h, params) => {
const row = params.row;
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
on: {
click: () => {
this.select(row);
}
}
}, '选择')
]);
},
}
],
tableData: []
}
},
created() {
this.query()
},
methods: {
filter() {
this.searchForm.pageNo = 1;
this.searchForm.pageSize = 10;
this.query();
},
changePageNo(pageNo) {
this.searchForm.pageNo = pageNo;
this.query();
},
select(row) {
this.$emit('selectPage', {
pageType: 2,
pageUrl: `${config.h5Host}/activity/${row.uuid}?tenantId=${row.tenantId}&vccToken={token}`,
pageName: row.pageName
});
},
async query() {
const res = await api.getPageList(this.searchForm);
this.total = res.total || 0;
this.tableData = res.data || []
},
reset() {
this.searchForm = {
pageName: '',
pageDescribe: '',
author: '',
pageSize: 10,
pageNo: 1
};
this.query();
},
}
}
</script>
<style scoped lang="less">
.comWidth {
width: 200px;
}
.search-bar{
width: 100%;
height: 50px;
.btnGroupStyle{
button{
margin-right: 6px;
}
}
/deep/ .ivu-form-item{
margin-bottom: 0;
}
/deep/ .ivu-form-item-label {
font-weight: bold;
display: inline-block;
}
/deep/.ivu-form-item-content {
display: inline-block;
}
}
.tableGroupStyle {
background: #fff;
.toolBarStyle {
display: flex;
justify-content: space-between;
align-items: center;
}
.pageStyle {
margin-top: 20px;
width: 100%;
text-align: right;
}
}
</style>
\ No newline at end of file
<template>
<Modal v-model="show" :title="title" width="500" :mask-closable="false" @on-cancel="close">
<div class="navigator-info">
<div class="navigator-info-name"><i>*</i>名称</div>
<div class="navigator-info-input">
<Input v-model="name" placeholder="仅用于内部运营人员识别使用" style="width: 300px" />
</div>
</div>
<div class="navigator-info">
<div class="navigator-info-name">导航背景色</div>
<div class="navigator-info-input color">
<Input class="color-input" v-model="bgColor" />
<ColorPicker v-model="bgColor" />
</div>
</div>
<div class="navigator-info">
<div class="navigator-info-name">导航背景图</div>
<div class="navigator-info-input">
<uploader v-model="bgImg" class="uploader" :showInput="false"/>
</div>
</div>
<div class="navigator-list">
<div
class="navigator-list-item"
v-for="(item, index) in navigatorData"
:key="index"
>
<div class="navigator-list-item_title">
<span>一级导航</span>
<div class="operation">
<Button type="primary" size="small" :disabled="index == 0" @click="sort(index, 1)">上移</Button>
<Button type="primary" size="small" :disabled="index == navigatorData.length - 1" @click="sort(index, 2)">下移</Button>
<Icon type="close-round" @click="deleteNavigatorConfigItem(index)"></Icon>
</div>
</div>
<div class="navigator-list-item_content">
<span><i>*</i>导航名称</span>
<Input v-model="item.name" placeholder="请输入导航名称" />
</div>
<div class="navigator-list-item_content">
<span><i>*</i>类型</span>
<div class="navigator-list-item_content_list">
<RadioGroup v-model="item.type">
<Radio :label="1">
<span>图文形式</span>
</Radio>
<Radio :label="2">
<span>纯图形式</span>
</Radio>
</RadioGroup>
</div>
</div>
<div class="navigator-list-item_content">
<span />
<div class="navigator-list-item_content_settings">
<div class="item">
<div class="label"><i>*</i>选中图标</div>
<div class="setting">
<uploader v-model="item.selectIcon" class="uploader" :showInput="false" />
</div>
</div>
<div class="item">
<div class="label"><i>*</i>未选中图标</div>
<div class="setting">
<uploader v-model="item.icon" class="uploader" :showInput="false" />
</div>
</div>
<div class="item" v-if="item.type == 1">
<div class="label"><i>*</i>选中文案颜色</div>
<div class="setting">
<Input class="color-input" v-model="item.selectColor" @on-blur="changeColor" />
<ColorPicker v-model="item.selectColor" />
</div>
</div>
<div class="item" v-if="item.type == 1">
<div class="label"><i>*</i>未选中文案颜色</div>
<div class="setting">
<Input class="color-input" v-model="item.color" @on-blur="changeColor" />
<ColorPicker v-model="item.color" />
</div>
</div>
</div>
</div>
<div class="navigator-list-item_content">
<span><i>*</i>选择页面</span>
<Button @click="clickSelectPageButton(index)">选择</Button>
</div>
<div class="navigator-list-item_content" v-if="item.pageType == 2">
<span>是否展示导航</span>
<Checkbox v-model="item.carryNav" />
</div>
<div class="navigator-list-item_content">
<span></span>
<span class="select" v-if="item.pageName && item.pageUrl">
{{item.pageName}}<template v-if="item.pageType != 1"> - {{item.pageUrl}}</template>
</span>
</div>
</div>
</div>
<div class="navigator-add">
<Button type="primary" icon="plus-round" id="add-button" long @click="addNavigatorConfig">新增一级导航</Button>
</div>
<div class="modal-footer" slot="footer">
<Button type="ghost" @click="close">取消</Button>
<Button type="primary" @click="confirm">保存</Button>
</div>
<div v-if="showSelectPageModal">
<Modal v-model="showSelectPageModal" :mask-closable="false" id="selectPageModal" title="选择页面" width="1000">
<Tabs :value="pageTabType">
<TabPane label="功能页面" name="1">
<featurePageTable
@selectPage="selectPage"
/>
</TabPane>
<TabPane label="活动页面" name="2">
<activityPageTable @selectPage="selectPage" />
</TabPane>
<TabPane label="导航页面" name="3">
<navigatorPageTable :nav-id="id" @selectPage="selectPage" />
</TabPane>
</Tabs>
<div slot="footer" />
</Modal>
</div>
</Modal>
</template>
<script>
import uploader from '../../../component/DynamicForm/component/Upload/index.vue';
import featurePageTable from './featurePageTable.vue';
import activityPageTable from './activityPageTable.vue';
import navigatorPageTable from './navigatorPageTable.vue';
import navigatorApi from '@api/navigator.api'
export default {
components: {
uploader,
featurePageTable,
activityPageTable,
navigatorPageTable
},
props: {
value: {
type: Boolean,
default: false
},
navigatorConfig: {
type: [Object, null],
default: null
}
},
watch: {
navigatorConfig: {
handler(val) {
this.title = val ? '编辑' : '新增'
if (val) {
const obj = Object.assign({}, val);
this.name = val.name;
this.id = val.id;
this.bgColor = val.bgColor;
this.bgImg = val.bgImg;
this.navigatorData = obj.navigatorData;
} else {
this.name = '';
this.id = '';
this.bgColor = '';
this.bgImg = '';
this.navigatorData = [];
}
},
immediate: true
}
},
computed: {
show: {
get() {
this.author = JSON.parse(localStorage.getItem('user')).account || '';
return this.value ? true : false;
},
set(v) {}
}
},
data() {
return {
title: '', // 弹窗标题
name: '', // 导航名称
navigatorData: [], // 导航配置
id: '',
author: '',
bgColor: '',
bgImg: '',
standardEditDataModel: { // 新增、编辑时会用到的标准导航数据模型
name: '',
type: 1,
color: '',
selectColor: '',
icon: '',
selectIcon: '',
pageType: '',
pageUrl: '',
pageName: '',
carryNav: true, // 是否携带导航
},
selectPageIndex: -1, // 选择页面 config索引
showSelectPageModal: false,
pageTabType: "1", // 标签页默认
}
},
methods: {
selectPage(data) {
// 选择页面
this.navigatorData[this.selectPageIndex].pageType = data.pageType;
this.navigatorData[this.selectPageIndex].pageUrl = data.pageUrl;
this.navigatorData[this.selectPageIndex].pageName = data.pageName;
this.showSelectPageModal = false;
},
clickSelectPageButton(index) {
this.selectPageIndex = index;
this.showSelectPageModal = true;
},
close() {
// 关闭事件
this.$emit('close')
this.resetData();
},
resetData() {
// 关闭前重置数据
this.name = '';
this.navigatorData = [];
this.id = '';
this.author = '';
this.bgColor = '';
this.bgImg = '';
},
addNavigatorConfig() {
// 添加导航配置
if (this.navigatorData.length === 5) {
return this.$toast('最多支持配置5个导航');
}
this.navigatorData.push(Object.assign({}, this.standardEditDataModel));
this.$nextTick(() => {
try {
document.getElementById('add-button').scrollIntoView();
} catch (e) {
console.log(e);
}
})
},
deleteNavigatorConfigItem(index) {
// 删除导航配置
this.navigatorData.splice(index, 1);
},
validate() {
const reg = /^(?:#[A-Fa-f0-9]{3}|#[A-Fa-f0-9]{6})$/;
// 校验值
if (!this.name) {
this.$toast('请填写名称');
return false;
}
if (!this.navigatorData.length) {
this.$toast('请配置导航');
return false;
}
if (this.navigatorData.length < 2 || this.navigatorData.length > 5) {
this.$toast('导航配置数量范围2-5个');
return false;
}
if (this.bgColor && !reg.test(this.bgColor)) {
this.$toast('导航背景色格式错误,请重新填写');
return false;
}
const arr = JSON.parse(JSON.stringify(this.navigatorData));
let navigatorNameExist = true; // 导航名称是否创建
let typeExist = true; // 导航类型是否选择(目前默认选择了图文形式)
for (let i = 0; i < arr.length; i++ ) {
if (!arr[i].name) {
navigatorNameExist = false;
}
if (!arr[i].type) {
typeExist = false;
}
if (arr[i].name && arr[i].name.length > 5) {
this.$toast('导航名称最大支持5个字符,请检查后重新填写');
return false;
}
if (
arr[i].type == 1
&&
(!arr[i].color || !arr[i].selectColor || !arr[i].icon || !arr[i].selectIcon)
) {
this.$toast('图文形式配置缺失,请填写后重试');
return false;
}
if(arr[i].type == 1 && (!reg.test(arr[i].color) || !reg.test(arr[i].selectColor))) {
this.$toast('导航文字颜色格式错误,请重新填写');
return false;
}
if (
arr[i].type == 2
&&
(!arr[i].icon || !arr[i].selectIcon)
) {
this.$toast('纯图形式配置缺失,请填写后重试');
return false;
}
if(!arr[i].pageName || !arr[i].pageUrl || !arr[i].pageType) {
this.$toast('请选择页面');
return false;
}
}
if (!navigatorNameExist) {
this.$toast('导航名称缺失,请填写后重试');
return false;
}
if (!typeExist) {
this.$toast('导航类型缺失,请选择后重试');
return false;
}
return true;
},
async confirm() {
// 提交
// 首先要进行校验
if (!this.validate()) return;
const params = {
name: this.name.trim(),
navigatorData: this.navigatorData,
author: this.author.trim(),
id: this.id,
bgColor: this.bgColor.trim(),
bgImg: this.bgImg.trim()
};
await navigatorApi.saveNavigator(params);
this.$toast('保存成功');
this.$emit('close', 1);
this.resetData();
},
changeColor(evnet, data) {
data = /^(?:#[A-Fa-f0-9]{3}|#[A-Fa-f0-9]{6})$/.test(evnet.target.value) ? evnet.target.value : ""
},
sort(index, type) {
/**
* feat: 上移下移
* index: 当前点击的元素索引
* type: 移动类型,1上移,2下移
*/
const arr = this.navigatorData.concat([]);
const targetIndex = type === 1 ? index - 1 : index + 1;
arr[index] = arr.splice(targetIndex, 1, arr[index])[0];
this.navigatorData = arr;
}
},
}
</script>
<style scoped lang="less">
#selectPageModal{
z-index: 1009;
/deep/ .ivu-modal-mask, /deep/ .ivu-modal-wrap{
z-index: 1009
}
/deep/ .ivu-modal-body{
height: 70vh;
overflow-y: auto;
}
}
/deep/ .ivu-modal-body{
max-height: 70vh;
overflow-y: auto;
}
.navigator-info{
width: 100%;
// height: 40px;
display: flex;
align-items: center;
margin-bottom: 20px;
&-name{
margin-right: 10px;
width: 80px;
text-align: right;
i{
color:#f00;
}
}
&-input{
&.color{
display: flex;
align-items: center;
.color-input{
margin-right: 10px;
}
}
}
}
.navigator-list{
&-item{
border: 1px solid #dddee1;
border-radius: 5px;
margin-top: 20px;
padding: 10px;
&_title{
display: flex;
align-items: center;
justify-content: space-between;
.operation{
display: flex;
align-items: center;
button{
margin-right: 12px;
&:first-child{
margin-right: 6px;
}
}
}
/deep/ .ivu-icon{
cursor: pointer;
}
}
&_content{
margin-top: 10px;
display: flex;
align-items: center;
span{
display: inline-block;
width: 80px;
flex-shrink: 0;
margin-right: 10px;
i{
color:#f00;
}
&.select{
display: inline-block; flex: 1;word-break:break-all
}
}
&_list{
display: flex;
align-items: center;
}
&_settings{
border-radius: 5px;
flex: 1;
padding: 10px;
border: 1px solid #dddee1;
.item{
margin-bottom: 10px;
min-height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
&:last-child{
margin-bottom: 0;
}
.label{
width: 100px;
flex-shrink: 0;
i{
color:#f00;
}
}
.setting{
display: flex;
align-items: center;
height: 100%;
flex: 1;
/deep/ .uploader{
width: 100%;
}
/deep/ .color-input{
width: 150px;
margin-right: 10px;
}
}
}
}
}
}
}
.navigator-add{
margin-top: 20px;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="expand-row" v-for="(item, idx) in row.navigatorData" :key="idx">
<div class="block"></div>
<div class="id">
<span class="expand-key">次序: </span>
<span class="expand-value">{{ idx + 1 }}</span>
</div>
<div class="name">
<span class="expand-key"></span>
<span class="expand-value">{{ item.name }}</span>
</div>
<div class="url">
<template v-if="item.pageType == 1">
{{item.pageName}}
</template>
<template v-else>
{{item.pageUrl}}
</template>
</div>
<div class="author">
<span class="expand-value">{{ row.author }}</span>
</div>
<div class="time">
<span class="expand-value">{{ row.updatedAt }}</span>
</div>
<div class="operation">
<span class="expand-value"><Button :disabled="item.pageType == 1" @click="select(item)" type="primary" size="small">选择</Button></span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
row: {
type: Object,
default: () => {}
},
index: {
type: [String, Number],
default: ''
}
},
methods: {
select(nav) {
const data = {};
data.pageType = 3;
data.pageName = nav.pageName;
data.pageUrl = nav.pageUrl;
this.$emit('select', data)
return;
}
}
};
</script>
<style scoped lang="less">
.expand-row{
display: flex;
align-items: center;
margin: 16px 0;
&>div{
word-break: break-all;
}
.block{
width: 40px;
flex-shrink: 0;
}
.id{
flex-shrink: 0;
width: 80px;
text-align: center;
}
.name{
flex-shrink: 0;
width: 160px;
text-align: center;
}
.url{
flex-shrink: 0;
width: 250px;
text-align: center;
}
.author{
flex-shrink: 0;
width: 90px;
text-align: center;
}
.time{
flex-shrink: 0;
width: 170px;
text-align: center;
}
.operation {
flex: 1;
text-align: center;
}
}
</style>
\ No newline at end of file
<template>
<div>
<Table
:columns="columns"
:data="tableData"
class="tableStyle"
/>
</div>
</template>
<script>
export default {
data() {
return {
columns: [
{
align: 'center',
title: '页面名称',
key: 'name',
},
{
align: 'center',
title: '操作',
render: (h, params) => {
const row = params.row;
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
on: {
click: () => {
this.select(row);
}
}
}, '选择')
]);
},
}
],
tableData: [
{
name: '首页tab',
url: 'home'
},
{
name: '购物车tab',
url: 'shopcart'
},
{
name: '我的tab',
url: 'user'
}
]
}
},
methods: {
select(row) {
this.$emit('selectPage', {
pageType: 1,
pageUrl: row.url,
pageName: row.name
});
}
}
}
</script>
\ No newline at end of file
<template>
<div>
<div class="search-bar">
<Form @submit.native.prevent inline ref="searchForm" :model="searchForm" class="inline">
<Form-item label="名称" prop="name">
<Input v-model="searchForm.name" class="comWidth" />
</Form-item>
<Form-item label="作者" prop="author">
<Input v-model="searchForm.author" class="comWidth" />
</Form-item>
<FormItem class="btnGroupStyle">
<div>
<Button class="btnStyle" @click="reset()">重置</Button>
<Button type="primary" class="btnStyle" @click="filter">查询</Button>
</div>
</FormItem>
</Form>
</div>
<div class="tableGroupStyle">
<Table
:columns="columns"
:data="tableData"
class="tableStyle"
/>
<Page
:total="total"
v-if="total > 0"
show-elevator
show-sizer
class="pageStyle"
:current="searchForm.pageNo"
:pageSize="searchForm.pageSize"
@on-change="changePageNo"
/>
<!-- @on-change="changePageNo"
@on-page-size-change="changePageSize" -->
</div>
</div>
</template>
<script>
import navigatorApi from '@api/navigator.api'
import expandRow from './expandRow.vue';
import config from '@/config/index';
export default {
props: {
navId: {
type: [Number, String],
default: ''
}
},
components: {
expandRow
},
data() {
return {
total: 0,
searchForm: {
name: '',
author: '',
pageSize: 10,
pageNo: 1
},
tableData: [],
columns: [
{
align: 'center',
title: '',
width: 40,
type: 'expand',
render: (h, params) => {
return h(expandRow, {
props: {
row: params.row,
index: params.index
},
on: {
select: (data) => {
this.$emit('selectPage', data);
}
}
})
}
},
{
align: 'center',
title: 'ID',
key: 'id',
width: 80,
},
{
align: 'center',
title: '名称',
width: 160,
key: 'name'
},
{
align: 'center',
title: '页面地址',
width: 250
},
{
align: 'center',
title: '作者',
key: 'author',
width: 90
},
{
align: 'center',
title: '更新时间',
key: 'updatedAt',
width: 170
},
{
align: 'center',
title: '操作',
key: 'operation'
}
]
}
},
created() {
this.query();
},
methods: {
filter() {
this.searchForm.pageNo = 1;
this.searchForm.pageSize = 10;
this.query();
},
reset() {
this.searchForm = {
name: '',
author: '',
pageSize: 10,
pageNo: 1
}
this.query();
},
async query() {
const queryParams = Object.assign({}, this.searchForm);
if (this.navId) {
queryParams.id = this.navId;
}
const res = await navigatorApi.getListWithRelation(queryParams);
this.total = res.total || 0;
if (res.data.length) {
for (let i = 0; i < res.data.length; i++) {
res.data[i]['_expanded'] = true;
}
}
this.tableData = res.data || []
},
changePageNo(pageNo) {
this.searchForm.pageNo = pageNo;
this.query();
},
}
}
</script>
<style scoped lang="less">
.comWidth {
width: 200px;
}
.search-bar{
width: 100%;
height: 50px;
.btnGroupStyle{
button{
margin-right: 6px;
}
}
/deep/ .ivu-form-item{
margin-bottom: 0;
}
/deep/ .ivu-form-item-label {
font-weight: bold;
display: inline-block;
}
/deep/.ivu-form-item-content {
display: inline-block;
}
}
.tableGroupStyle {
background: #fff;
.toolBarStyle {
display: flex;
justify-content: space-between;
align-items: center;
}
.pageStyle {
margin-top: 20px;
width: 100%;
text-align: right;
}
}
/deep/ .ivu-table-expanded-cell{
padding: 0;
}
</style>
\ No newline at end of file
<template>
<div class="tableComStyle">
<div class="searchFormStyle">
<Form @submit.native.prevent inline ref="searchForm" :model="searchForm" class="inline">
<Form-item label="名称" prop="name">
<Input v-model="searchForm.name" class="comWidth" placeholder="请输入名称" />
</Form-item>
<Form-item label="作者" prop="author">
<Input v-model="searchForm.author" class="comWidth" placeholder="请输入作者" />
</Form-item>
<FormItem class="btnGroupStyle">
<div>
<Button class="btnStyle" @click="reset()">重置</Button>
<Button type="primary" class="btnStyle" @click="query">查询</Button>
</div>
</FormItem>
</Form>
</div>
<div class="tableGroupStyle">
<div class="toolBarStyle">
<h3>查询数据</h3>
<div>
<Button type="primary" class="btnStyle" @click="add">新增</Button>
<slot></slot>
</div>
</div>
<Table
:columns="columns"
:data="tableData"
class="tableStyle"
/>
<Page
:total="total"
v-if="total > 0"
show-elevator
show-sizer
class="pageStyle"
:current="searchForm.pageNo"
:pageSize="searchForm.pageSize"
@on-change="changePageNo"
@on-page-size-change="changePageSize"
/>
</div>
<Modal v-model="showPagesUrl" title="页面地址列表" width="900">
<Table
:columns="urlTableColumns"
:data="urlTableData"
class="tableStyle"
/>
<span slot="footer"></span>
</Modal>
<addOrEditNavigator
v-model="showAddOrEdit"
:navigatorConfig="navigatorConfig"
@close="closeAddOrEdit"
/>
</div>
</template>
<script>
import { columns, urlTableColumns } from '@/config/navigatorCol.config'
import navigatorApi from '@api/navigator.api'
import addOrEditNavigator from './components/addOrEditNavigator'
export default {
components: {
addOrEditNavigator
},
data() {
return {
showPagesUrl: false,
searchForm: {
pageSize: 20,
pageNo: 1,
name: '',
author: ''
},
tableData: [],
urlTableData: [],
columns: [],
urlTableColumns: [],
total: 0,
navigatorConfig: null, // 新增、编辑的配置
showAddOrEdit: false
}
},
created() {
this.columns = columns(this);
this.urlTableColumns = urlTableColumns(this);
this.$nextTick(() => {
this.query();
})
},
methods: {
async query() {
const res = await navigatorApi.getList(this.searchForm);
this.total = res.total || 0;
this.tableData = res.data || []
},
closeAddOrEdit(refresh){
this.showAddOrEdit = false;
this.navigatorConfig = null;
if (refresh) {
this.query();
}
},
add() {
this.navigatorConfig = null;
this.showAddOrEdit = true;
},
changePageSize(size) {
// 变更每页条数
this.searchForm.pageNo = 1;
this.searchForm.pageSize = size;
this.query();
},
changePageNo(page) {
// 变更页码
this.searchForm.pageNo = page;
this.query();
},
showAddr(row) {
// 查看地址列表
let configs = row.navigatorData || [];
let arr = [];
for (let i = 0; i < configs.length; i++) {
let obj = {};
obj.id = i + 1;
obj.configName = configs[i].name;
obj.pageName = configs[i].pageName;
obj.pageUrl = configs[i].pageType == 1 ? '' : configs[i].pageUrl;
arr.push(obj)
}
this.urlTableData = arr;
this.showPagesUrl = true;
},
preview(row) {
// 预览,默认预览第一个导航页面
console.log(row);
},
edit(row) {
// 编辑
this.navigatorConfig = row;
this.showAddOrEdit = true;
},
delete(row) {
// 删除
this.$Modal.confirm({
title: '提示',
content: `是否删除导航 ${row.name}`,
onOk: async () => {
const deleteRes = await navigatorApi.deleteNavigator({
id: row.id
});
this.$toast('删除成功');
this.query();
}
})
},
reset() {
// 重置表单
// this.resetForm('searchForm');
this.$refs.searchForm.resetFields();
this.searchForm.pageSize = 20;
this.searchForm.pageNo = 1;
this.searchForm.name = '';
this.searchForm.author = '';
this.$nextTick(() => {
this.query();
})
},
}
}
</script>
<style scoped lang="less">
@padding: 25px;
.tableStyle {
margin-top: 15px;
}
.inline {
display: inline-block;
}
.comWidth {
width: 200px;
}
.tableComStyle {
height: 100%;
background: #f5f5f5;
padding: 15px;
// min-height: 1000px;
.searchFormStyle {
text-align: left;
clear: both;
background-color: #fff;
padding: @padding;
min-height: 70px;
font-size: 0;
.btnGroupStyle{
button{
margin-right: 6px;
}
}
/deep/ .ivu-form-item{
margin-bottom: 0;
}
/deep/ .ivu-form-item-label {
font-weight: bold;
display: inline-block;
}
/deep/.ivu-form-item-content {
display: inline-block;
}
}
.tableGroupStyle {
background: #fff;
padding: @padding;
margin-top: 15px;
.toolBarStyle {
display: flex;
justify-content: space-between;
align-items: center;
}
.pageStyle {
margin-top: 20px;
width: 100%;
text-align: right;
}
}
}
</style>
\ No newline at end of file
......@@ -4,6 +4,7 @@
:columns="columns"
:request="query"
@newBtnClick="addPage"
@clearCache="refreshData"
>
</QGTable>
</template>
......
......@@ -8,7 +8,7 @@
"test": "cross-env NODE_ENV=production EGG_SERVER_ENV=sit egg-scripts start --port 80 --workers 1",
"stop": "egg-scripts stop",
"backend": "nohup egg-scripts start --port 7001 --workers 4",
"dev": "cross-env NODE_ENV=test APOLLO_CLUSTER=k8s NAMESPACE=test1 npm run apollo && egg-bin dev -r egg-ts-helper/register --port 7002",
"dev": "cross-env NODE_ENV=test APOLLO_CLUSTER=k8s NAMESPACE=qa npm run apollo && egg-bin dev -r egg-ts-helper/register --port 7002",
"debug": "egg-bin debug -r egg-ts-helper/register",
"apollo": "node bin/apollo.js",
"build": "cross-env NODE_ENV=production APOLLO_CLUSTER=3C npm run apollo && cross-env COS_ENV=production easy build --devtool",
......
......@@ -3,9 +3,11 @@
import 'egg';
import ExportEditor from '../../../app/controller/editor';
import ExportNavigator from '../../../app/controller/navigator';
declare module 'egg' {
interface IController {
editor: ExportEditor;
navigator: ExportNavigator;
}
}
......@@ -2,11 +2,13 @@
// Do not modify this file!!!!!!!!!
import 'egg';
import ExportNavigatorConfig from '../../../app/model/navigatorConfig';
import ExportPageInfo from '../../../app/model/pageInfo';
import ExportTenantAuth from '../../../app/model/tenantAuth';
declare module 'egg' {
interface IModel {
NavigatorConfig: ReturnType<typeof ExportNavigatorConfig>;
PageInfo: ReturnType<typeof ExportPageInfo>;
TenantAuth: ReturnType<typeof ExportTenantAuth>;
}
......
......@@ -6,10 +6,12 @@ type AnyClass = new (...args: any[]) => any;
type AnyFunc<T = any> = (...args: any[]) => T;
type CanExportFunc = AnyFunc<Promise<any>> | AnyFunc<IterableIterator<any>>;
type AutoInstanceType<T, U = T extends CanExportFunc ? T : T extends AnyFunc ? ReturnType<T> : T> = U extends AnyClass ? InstanceType<U> : U;
import ExportNavigator from '../../../app/service/navigator';
import ExportRedis from '../../../app/service/redis';
declare module 'egg' {
interface IService {
navigator: AutoInstanceType<typeof ExportNavigator>;
redis: AutoInstanceType<typeof ExportRedis>;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment