Commit a219ac51 authored by rockyl's avatar rockyl

完成开发

parent bd24ef18
......@@ -55,6 +55,7 @@
"Path": "路径",
"Timeout": "超时(ms)",
"SuccessRatio": "成功率",
"Operate success": "操作成功",
"Data": "数据",
"Key": "属性名",
"Default": "默认值",
......@@ -182,9 +183,24 @@
"Dependencies missing": "依赖缺失",
"missingDependenciesNotice": "<i class=\"el-icon-warning\"></i>依赖缺失,请到【<span style=\"font-weight: bold,\">详情>包管理</span>】进行安装",
"Pack manager": "打包管理",
"Publish": "发布",
"Publish config": "发布配置",
"Publish to projectx": "发布到星速台",
"Are sure to delete this item?": "确定要删除这条记录吗?",
"Projectx skin editor": "星速台皮肤编辑器",
"Skin name required": "皮肤名必填",
"Skin html required": "皮肤代码必填",
"Skin name": "皮肤名",
"Skin html": "皮肤代码",
"Copy skin success": "复制皮肤成功",
"Copy url success": "复制链接成功",
"Copy skin": "复制皮肤",
"Copy url": "复制链接",
"ID required": "ID必填",
"Name required": "名字必填",
"Index page exists": "已存在首页",
"Please config projectID": "请先配置{env}环境下的projectId",
"Online ticket is invalid": "线上tickct失效,请联系管理员修改",
"eventGroup": {
"in": "接收",
"out": "派发"
......@@ -208,6 +224,9 @@
"mock": {
"label": "Mock"
},
"px-skin-editor": {
"label": "皮肤"
},
"exit": {
"label": "退出"
},
......
......@@ -65,18 +65,18 @@ export const packageStore = {
}
];
const dividerProcess = {
id: 'divider',
name: 'Divider',
desc: i18n.t('Divider node desc'),
};
normalsTree.push(dividerProcess);
const customProcess = {
id: 'custom',
name: 'Custom',
desc: i18n.t('Custom node desc'),
};
normalsTree.push(customProcess);
const dividerProcess = {
id: 'divider',
name: 'Divider',
desc: i18n.t('Divider node desc'),
};
normalsTree.push(dividerProcess);
normalsTree.push({
name: 'builtin',
......
......@@ -329,6 +329,10 @@ $dock-pin-width: 9px;
padding: 5px;
flex-direction: column;
.el-form-item--mini.el-form-item {
margin-bottom: 3px;
}
.info-editor {
margin-right: 5px;
}
......
......@@ -237,6 +237,53 @@
}
}
.px-skin-editor-dialog {
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
.env-select {
align-self: flex-end;
}
.operate-wrapper > :not(*:first-child) {
margin-left: 10px;
}
}
.popover-px-config {
margin-left: 10px;
}
}
.px-skin-editor {
.wrapper {
height: 50vh;
.form{
height: 100%;
display: flex;
flex-direction: column;
.editor-form-item{
flex: 1;
.el-form-item__content {
height: 100%;
.editor {
height: 100%;
}
}
}
}
}
}
.dialog-footer {
display: flex;
justify-content: space-between;
......@@ -303,26 +350,27 @@
.scrollbar {
height: 50vh;
.popover-publish{
.popover-publish {
//margin-right: 10px;
}
.pack-list > :not(*:first-child){
.operate-wrapper > :not(*:first-child) {
margin-left: 10px;
}
}
.popover-px-config{
.popover-px-config {
margin-left: 10px;
}
}
.project-x-config{
.input{
flex:1;
.project-x-config {
.input {
flex: 1;
}
.bottom-bar{
.bottom-bar {
display: flex;
justify-content: space-between;
margin-top: 10px;
......
......@@ -63,10 +63,6 @@
padding-right: 5px;
}
.el-form-item--mini.el-form-item {
margin-bottom: 3px;
}
.el-textarea__inner {
height: 100%;
}
......
......@@ -26,6 +26,12 @@ export const typeMapping = [
'custom',
];
export const pxHostMapping = {
dev: "activity.m.duibadev.com.cn",
test: "activity.m.duibatest.com.cn",
prod: "https://activity.m.duiba.com.cn"
};
/**
* 节点方案
* @type {string}
......
......@@ -17,6 +17,7 @@
<mock-editor-dialog ref="mockEditorDialog"/>
<code-sync-serve-dialog ref="codeSyncServeDialog"/>
<missing-packages-dialog ref="missingPackagesDialog"/>
<px-skin-editor-dialog ref="pxSkinEditorDialog"/>
</div>
</template>
......@@ -39,10 +40,12 @@
import CodeSyncServeDialog from "./Editor/dialogs/CodeSyncServeDialog";
import MissingPackagesDialog from "./Editor/dialogs/MissingPackagesDialog";
import PackManagerDialog from "./Editor/dialogs/PackManagerDialog";
import PxSkinEditorDialog from "./Editor/dialogs/PxSkinEditorDialog";
export default {
name: 'Editor',
components: {
PxSkinEditorDialog,
PackManagerDialog,
MissingPackagesDialog,
CodeSyncServeDialog,
......@@ -235,6 +238,9 @@
case 'redo':
this.$store.commit('undoRedo', -1);
break;
case 'px-skin-editor':
this.$refs.pxSkinEditorDialog.show();
break;
case 'exit':
const {projectID} = this.$route.params;
if (await this.localVersionExist(projectID)) {
......
......@@ -141,8 +141,8 @@ export default {
exposeVariables,
rules: {
id: [{ required: true, trigger: "blur" }],
name: [{ required: true, trigger: "blur" }]
id: [{ required: true, trigger: "blur", }],//message: this.$t('ID required')
name: [{ required: true, trigger: "blur", }],//message: this.$t('Name required')
},
};
},
......
......@@ -97,7 +97,7 @@ $ENV_PROPS$
.replace('$OUTPUT_TYPES$', outputTypes)
.replace('$PROPS_TYPES$', props.join('\n'))
.replace('$ENV_PROPS$', envKeys.join('\n'))
console.log(metaDts);
//console.log(metaDts);
this.monaco.languages.typescript.javascriptDefaults.addExtraLib(metaDts, 'meta.d.ts');
},
}
......
<template>
<el-popover
class="popover-px-config"
placement="top"
:title="$t('Projectx config')"
v-model="popoverPxConfigVisible"
@show="onPopoverPxConfigShow"
>
<projectx-config ref="pxConfig" @save="onSavePxConfig" :show-bottom-bar="true"/>
<el-button
slot="reference"
size="mini" plain>
{{$t('Publish config')}}
</el-button>
</el-popover>
</template>
<script>
import ProjectxConfig from "../dialogs/editors/ProjectxConfig";
export default {
name: "PxConfigPopover",
components: {ProjectxConfig},
data(){
return {
popoverPxConfigVisible: false,
}
},
methods: {
onSavePxConfig() {
this.popoverPxConfigVisible = false;
this.$emit('save');
},
onPopoverPxConfigShow() {
this.$refs.pxConfig.edit();
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -28,8 +28,8 @@
</el-popover>
</template>
</el-table-column>
<el-table-column width="180px">
<div class="pack-list" slot-scope="scope">
<el-table-column width="240px">
<div class="operate-wrapper" slot-scope="scope">
<el-popover
class="popover-publish"
placement="bottom"
......@@ -40,26 +40,23 @@
<publish-view :ref="'popoverPublish_' + scope.$index"></publish-view>
<el-button
slot="reference"
icon="el-icon-s-promotion"
size="mini" plain
type="primary"
/>
>{{$t('Publish')}}</el-button>
</el-popover>
<el-button
icon="el-icon-document-copy"
size="mini" plain
type="success"
@click="copyTpl(scope.row.packResult.tpl)"
/>
>{{$t('Copy skin')}}</el-button>
<el-popconfirm :title="$t('Are sure to delete this item?')"
@onConfirm="deleteItem(scope.row.id)"
placement="top">
<el-button
slot="reference"
icon="el-icon-delete"
size="mini" plain
type="danger"
/>
>{{$t('Delete')}}</el-button>
</el-popconfirm>
</div>
</el-table-column>
......@@ -69,21 +66,7 @@
<div slot="footer" class="dialog-footer">
<div>
<el-button type="primary" size="mini" @click="onPack">{{ $t("Pack") }}</el-button>
<el-popover
class="popover-px-config"
placement="top"
:title="$t('Projectx config')"
v-model="popoverPxConfigVisible"
@show="onPopoverPxConfigShow"
>
<projectx-config ref="pxConfig" @save="onSavePxConfig" :show-bottom-bar="true"/>
<el-button
slot="reference"
size="mini" plain>
{{$t('Publish config')}}
</el-button>
</el-popover>
<px-config-popover/>
</div>
<div>
<el-button size="mini" @click="onClose">{{ $t("Close") }}</el-button>
......@@ -97,15 +80,14 @@
import copy from 'copy-to-clipboard'
import PublishView from "./PublishView";
import {openPreview} from "../../../utils";
import ProjectxConfig from "./editors/ProjectxConfig";
import PxConfigPopover from "../components/PxConfigPopover";
export default {
name: "PackManagerDialog",
components: {ProjectxConfig, PublishView},
components: {PxConfigPopover, PublishView},
data() {
return {
visible: false,
popoverPxConfigVisible: false,
isSaveProjecx: false,
activeName: 'project',
historyItems: [],
......@@ -125,14 +107,12 @@
onClose() {
this.visible = false;
},
onSavePxConfig() {
this.popoverPxConfigVisible = false;
},
onPopoverPxConfigShow() {
this.$refs.pxConfig.edit();
},
copyTpl(tpl) {
copy(tpl);
this.$message({
message: this.$t('Copy skin success'),
type: "success"
});
},
async deleteItem(id) {
await this.deletePackItem(id);
......
......@@ -32,7 +32,7 @@
</template>
<script>
import {mapState} from "vuex";
import {mapGetters} from "vuex";
import copy from "copy-to-clipboard";
import {
getProjectSkins,
......@@ -41,12 +41,7 @@
getProdTicket,
sendDingTalk
} from "../../../../src/api/polaris";
const mapping = {
dev: "activity.m.duibadev.com.cn",
test: "activity.m.duibatest.com.cn",
prod: "https://activity.m.duiba.com.cn"
};
import {pxHostMapping} from "../../../utils";
export default {
name: "PublishView",
......@@ -70,7 +65,7 @@
};
},
computed: {
...mapState(["project"])
...mapGetters(["options"])
},
methods: {
async active(tpl) {
......@@ -90,7 +85,7 @@
await this.getTicket(getProdTicket, "prod_ticket");
}
const {pxEnv} = this.project.data.options;
const {pxEnv} = this.options;
const pxPid = this.pxPid = pxEnv[env];
if (!pxPid) {
......@@ -194,7 +189,7 @@
type = skin.type;
}
});
const url = `${mapping[env]}/projectx/${projectId}/${
const url = `${pxHostMapping[env]}/projectx/${projectId}/${
type === "1" ? "index" : skinId
}.html`;
copy(url);
......
<template>
<el-dialog
:title="$t('Projectx skin editor')"
width="80vw"
:visible.sync="visible"
:append-to-body="true"
:close-on-click-modal="false"
:show-close="false"
:close-on-press-escape="false"
custom-class="px-skin-editor"
>
<div class="wrapper" v-if="skin">
<el-form class="form" ref="form" :model="skin" :rules="rules" size="mini" label-width="80px">
<el-form-item :label="$t('Skin name')" prop="name">
<el-input v-model="skin.name" :placeholder="$t('Skin name')"/>
</el-form-item>
<el-form-item :label="$t('Skin html')" prop="html" class="editor-form-item">
<monaco-editor
class="editor"
v-model="skin.html"
language="html"
/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<div>
</div>
<div>
<el-button size="mini" @click="clickClose">{{ $t("Close") }}</el-button>
<el-button type="primary" size="mini" @click="clickSave">{{ $t("Save") }}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import MonacoEditor from "vue-monaco";
import {clonePureObj} from "../../../utils";
import ElFormItem from "../../../components/inputs/form-item";
export default {
name: "PxSkinEditor",
components: {ElFormItem, MonacoEditor},
data() {
return {
visible: false,
skin: null,
operate: 0,
rules: {
name: [
{required: true, message: this.$t('Skin name required'), trigger: 'blur'},
],
/*html: [
{required: true, message: this.$t('Skin html required'), trigger: 'blur'},
],*/
}
}
},
methods: {
async edit(operate, skin) {
this.operate = operate;
this.skin = clonePureObj(skin);
if (!this.skin.html) {
this.skin.html = '';
}
this.visible = true;
},
clickSave() {
if(!this.skin.html){
this.$message(this.$t('Skin html required'));
}else{
this.$refs.form.validate(async (valid) => {
if (valid) {
try {
this.$emit('input', this.skin, this.operate);
} catch (e) {
console.warn(e);
}
}
});
}
},
clickClose() {
this.visible = false;
},
onSaveSuccess() {
this.clickClose();
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<el-dialog :title="$t('Projectx skin editor')" width="70%" :visible.sync="visible"
:close-on-click-modal="false"
:append-to-body="true"
:show-close="false"
fullscreen
custom-class="flex-dialog px-skin-editor-dialog"
>
<div class="wrapper">
<el-select class="env-select" size="mini" v-model="env" @change="changeEnv">
<el-option v-for="(item, key) in pxEnvs" :key="key" :label="item" :value="key"></el-option>
</el-select>
<el-table class="mock-table" :data="skins" height="100%" stripe size="mini">
<el-table-column
prop="id"
label="ID"
width="100">
</el-table-column>
<el-table-column
:label="$t('Type')"
width="100">
<template slot-scope="scope">
<span>{{tplTypes[scope.row.type - 1]}}</span>
</template>
</el-table-column>
<el-table-column
prop="name"
:label="$t('Name')">
</el-table-column>
<el-table-column width="240">
<div class="operate-wrapper" slot-scope="scope">
<el-button
size="mini" plain
type="primary"
@click="editItem(scope.row)"
>{{$t('Edit')}}
</el-button>
<el-button
size="mini" plain
type="success"
@click="copyUrl(scope.row)"
>{{$t('Copy url')}}
</el-button>
<el-popconfirm :title="$t('Are sure to delete this item?')"
@onConfirm="deleteItem(scope.row)"
placement="top">
<el-button
slot="reference"
size="mini" plain
type="danger"
>{{$t('Delete')}}
</el-button>
</el-popconfirm>
</div>
</el-table-column>
</el-table>
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-dropdown trigger="click" @command="onAdd" placement="top" size="small">
<el-button size="mini" icon="el-icon-plus" type="primary">{{$t('Add')}}</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(type, index) of tplTypes" :command="index" :key="index">{{type}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<px-config-popover @save="onSavePxConfig"/>
</div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
</div>
</div>
<px-skin-editor ref="pxSkinEditor" @input="onSaveSkin"/>
</el-dialog>
</template>
<script>
import {mapGetters, mapMutations, mapActions} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import MonacoEditor from "vue-monaco";
import PxConfigPopover from "../components/PxConfigPopover";
import {getProdTicket, getProjectSkins, getTestEnvTicket, saveSkins} from "../../../api/polaris";
import {playWaiting, pxHostMapping} from "../../../utils";
import copy from "copy-to-clipboard";
import PxSkinEditor from "./PxSkinEditor";
export default {
name: "PxSkinEditorDialog",
components: {PxSkinEditor, PxConfigPopover, MonacoEditor, EnabledSetter},
data() {
return {
visible: false,
pxEnvs: this.$t("pxEnvs"),
tplTypes: this.$t("tplTypes"),
skins: [],
env: 'dev',
}
},
computed: {
...mapGetters(["options", 'project'])
},
methods: {
hasIndex() {
return this.skins.find(v => v.type === "1");
},
show() {
this.visible = true;
},
onClose() {
this.visible = false;
},
onAdd(type) {
if (type === 0 && this.hasIndex()) {
this.$message({message: this.$t('Index page exists'), type: "warning"});
} else {
this.$refs.pxSkinEditor.edit(0, {type: (type + 1).toString()});
}
},
editItem(skin) {
this.$refs.pxSkinEditor.edit(1, skin);
},
copyUrl(skin) {
const {id, type} = skin;
let pxPid = this.options.pxEnv[this.env];
const url = `${pxHostMapping[this.env]}/projectx/${pxPid}/${
type === "1" ? "index" : id
}.html`;
copy(url);
this.$message({
message: this.$t('Copy url success'),
type: "success"
});
},
deleteItem(skin) {
try {
this.saveSkin(skin, 2);
} catch (e) {
throw new Error(e.message);
}
},
async onSaveSkin(skin, operate) {
try {
await this.saveSkin(skin, operate);
this.$refs.pxSkinEditor.onSaveSuccess();
} catch (e) {
throw new Error(e.message);
}
},
async changeEnv(e) {
await this.getSkinsList();
},
onSavePxConfig() {
this.getSkinsList();
},
async getSkinsList() {
const {env} = this;
if (env === "test") {
await this.getTicket(getTestEnvTicket);
} else if (env === "prod") {
await this.getTicket(getProdTicket, "prod_ticket");
}
const {pxEnv} = this.options;
const pxPid = this.pxPid = pxEnv[env];
if (!pxPid) {
this.$message({
message: this.$t('Please config projectID', {env}),
type: "error"
});
return;
}
try {
const data = await getProjectSkins(pxPid, env);
if (data.success !== false) {
this.skins = data;
} else {
// 如果是测试环境,ticket过期,则重新获取ticket
if (env === "test" && data.notLogin) {
localStorage.setItem("ticket", "");
await this.getTicket(getTestEnvTicket);
this.getSkinsList(this.projectId);
} else if (env === "prod" && data.notLogin) {
localStorage.setItem("prod_ticket", "");
this.$message({
message: this.$('Online ticket is invalid'),
type: "info"
});
this.skins = [];
} else {
this.$message({
message: data.message,
type: "error"
});
this.skins = [];
}
}
} catch (e) {
throw new Error(e.message);
}
},
async getTicket(fn, name = "ticket") {
let ticket = localStorage.getItem(name);
if (!ticket) {
ticket = await fn();
localStorage.setItem(name, ticket);
}
},
async saveSkin(skin, operate) {
const {
env,
pxPid,
} = this;
const {id, html, name, type} = skin;
const data = {
projectId: pxPid,
type: (operate + 1).toString(),
currentHtmlType: type,
skinId: id,
tpl: html,
name,
env,
};
const {ret} = await playWaiting(saveSkins(data), this.$t('In processing'));
if (ret.success !== false) {
this.$message({
message: this.$t('Operate success'),
type: "success"
});
} else {
this.$message({message: ret.message, type: "error"});
}
if (operate !== 1) {
this.getSkinsList();
}
},
...mapMutations([
'modifyMocks',
]),
...mapActions([
'setMockServeEnabled',
]),
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -70,13 +70,11 @@
},
computed: {
...mapState({
customs(state) {
console.log(state.editor.customs);
return state.editor.customs;
},
customs: state => state.project.data.customs,
}),
...mapGetters([
'assets',
'customPackages',
])
},
methods: {
......@@ -108,7 +106,7 @@
},
show(data) {
this.mid = data.id;
this.customMeta = clonePureObj(this.customs.find(item => item.id === this.mid));
this.customMeta = clonePureObj(this.customPackages[this.mid]);
for (let uuid in data.assetMapping) {
let asset = this.customMeta.assets.find(item => item.uuid === uuid);
......
......@@ -93,6 +93,7 @@
const {projectID} = this.$route.params;
const {data, tpl} = await db.get('preview', projectID);
console.log(data);
//console.log(JSON.stringify(data.processes));
let {options: {pageTitle, }, } = data;
document.title = pageTitle;
......
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