Commit d60fcb79 authored by rockyl's avatar rockyl

版本库锁定完成开发

parent 4a6afcb8
......@@ -4,9 +4,10 @@
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"upload": "node scripts/copy-index.js && ali-oss-publish -c oss.config.js -e dist",
"upload": "node scripts/pre-process.js && ali-oss-publish -c oss.config.js -e dist",
"build:upload": "npm run build&&npm run upload",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'"
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
"link:all": "yarn link zeroing-code-divider zeroing-template-fill props-compute"
},
"dependencies": {
"codemirror": "^5.50.0",
......@@ -18,11 +19,11 @@
"indexdbwrapper": "^1.0.4",
"jszip": "^3.2.2",
"moment": "^2.24.0",
"monaco-editor": "^0.19.0",
"monaco-editor-webpack-plugin": "^1.8.1",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"path": "^0.12.7",
"psd-parse-web": "http://gitlab2.dui88.com/laoqifeng/psd-parse-web.git",
"props-compute": "http://gitlab2.dui88.com/laoqifeng/props-compute.git",
"psd-parse-web": "http://gitlab2.dui88.com/laoqifeng/psd-parse-web.git",
"querystringify": "^2.1.1",
"semver": "^7.1.1",
"socket.io-client": "^2.3.0",
......@@ -30,11 +31,12 @@
"string-width": "^4.1.0",
"uuid": "^3.3.3",
"vue": "^2.6.10",
"vue-codemirror": "^4.0.6",
"vue-i18n": "^8.0.0",
"vue-monaco": "http://gitlab2.dui88.com/laoqifeng/vue-monaco.git",
"vue-router": "^3.0.3",
"vuex": "^3.0.1",
"zeroing-code-divider": "http://gitlab2.dui88.com/laoqifeng/zeroing-code-divider.git"
"zeroing-code-divider": "http://gitlab2.dui88.com/laoqifeng/zeroing-code-divider.git",
"zeroing-template-fill": "http://gitlab2.dui88.com/laoqifeng/zeroing-template-fill.git"
},
"devDependencies": {
"@kazupon/vue-i18n-loader": "^0.3.0",
......
......@@ -7,8 +7,6 @@
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>烽火台</title>
<script src="//yun.duiba.com.cn/js-libs/jshint/2.10.2/jshint.min.js"></script>
<script src="//yun.duiba.com.cn/js-libs/jsonlint/1.6.0/jsonlint.min.js"></script>
<script src="//yun.duiba.com.cn/js-libs/psd.js/3.2.0/psd.min.js"></script>
</head>
<body>
......
<template>
<div style="width: 100%; height: 100%" ref="container"></div>
</template>
<script>
import * as monaco from 'monaco-editor';
export default {
name: "MonacoEditor",
data() {
return {
}
},
props: {
value: {
type: String,
default: '',
},
language: {
type: String,
default: 'javascript',
},
theme: {
type: String,
default: 'vs',
},
editorOptions: {
type: Object,
default: function(){
return {
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: false, // 只读
cursorStyle: 'line', //光标样式
automaticLayout: false, //自动布局
glyphMargin: true, //字形边缘
useTabStops: false,
fontSize: 28, //字体大小
autoIndent:true,//自动布局
}
},
},
},
mounted() {
this.initEditor();
},
watch: {
value(value){
if(this.editor && value !== this.editor.getValue()){
this.editor.setValue(value);
}
}
},
methods: {
initEditor() {
this.editor = monaco.editor.create(this.$refs.container, {
value: this.value,
language: this.language,
theme: this.theme,
lineNumbers: 'on',
tabSize: 2,
insertSpaces: false,
editorOptions: this.editorOptions,
});
this.editor.onDidChangeModelContent(event => {
const value = this.editor.getValue();
this.$emit('input', value);
});
this.editor.updateOptions({
})
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -6,8 +6,8 @@ export let API_HOST;
if (process.env.NODE_ENV === 'development') {
//API_HOST = '//10.10.95.74:7777';
//API_HOST = '//192.168.1.16:7777';
API_HOST = '//192.168.2.143:7777';
//API_HOST = '//10.10.92.33:7777';
API_HOST = '//10.10.92.100:7777';
//API_HOST = '//192.168.0.106:7777';
//API_HOST = '//localhost:3002';
//API_HOST = window.__data.apiHost;
//API_HOST = '';
......
......@@ -3,13 +3,15 @@
"Confirm": "确认",
"Cancel": "取消",
"Close": "关闭",
"Still Close": "仍然关闭",
"Refresh": "刷新",
"Still Close": "直接关闭",
"Save": "保存",
"Save And Preview": "保存并预览",
"Save And Close": "保存并关闭",
"Reset": "重置",
"Copy": "复制",
"Assets": "素材",
"Version": "版本",
"Paste same level":"粘贴(同级)",
"Paste child":"粘贴(子级)",
"Exit": "退出",
......@@ -173,6 +175,9 @@
"Import view success": "视图导入成功",
"Input projectx id": "请输入{envName}星速台项目ID",
"Save template to projectx": "是否保存皮肤到星速台",
"All versions": "全部版本",
"Dependencies missing": "依赖缺失",
"missingDependenciesNotice": "<i class=\"el-icon-warning\"></i>依赖缺失,请到【<span style=\"font-weight: bold,\">详情>包管理</span>】进行安装",
"eventGroup": {
"in": "接收",
"out": "派发"
......@@ -296,8 +301,9 @@
"race": "负责最先"
},
"dependenciesTypes": {
"library": "运行时库",
"process": "过程库",
"custom": "模块库",
"script": "脚本库"
"script": "脚本库",
"custom": "模块库"
}
}
\ No newline at end of file
......@@ -4,13 +4,13 @@ import router from './router'
import store from './store/index'
import i18n from './i18n'
import './vue-resize'
Vue.config.productionTip = false;
import './time-format-plugin'
import './assets/style.css'
import './plugins/element.js'
import './themes/light/index.scss'
Vue.config.productionTip = false;
import './token'
new Vue({
......
......@@ -12,10 +12,11 @@ import {arrayFind} from "element-ui/src/utils/util";
export const behaviorStore = {
state: {
data: {},
projectData: {},
processes: null,
originProcesses: null,
currentBehavior: null,
processContext: [],
originData: null,
currentProcess: null,
processStack: [],
......@@ -27,33 +28,44 @@ export const behaviorStore = {
boardOffset: {x: 0, y: 0},
boardScale: 1,
},
dirty: false,
},
mutations: {
makeBehaviorDirty(state){
state.dirty = true;
},
behavior_startEdit(state, {originData, behavior}) {
state.originData = originData;
state.data = clonePureObj(originData);
state.dirty = false;
state.projectData = originData;
state.originProcesses = originData.processes;
state.processes = clonePureObj(originData.processes);
state.currentBehavior = clonePureObj(behavior);
this.commit('updateCustomProcesses', state.processes);
},
behavior_save(state) {
state.originData.processes = state.data.processes;
state.originProcesses.splice(0);
state.originProcesses.push(...state.processes);
},
addProcessMeta(state, meta) {
state.data.processes.push(meta);
state.processes.push(meta);
this.commit('makeBehaviorDirty');
return process;
},
updateProcesses(state, {targetMetaID, replaceMetaID}) {
updateProcesses(state.data.processes, targetMetaID, replaceMetaID);
updateProcesses(state.processes, targetMetaID, replaceMetaID);
},
deleteProcessMeta(state, {meta, process}) {
let container;
if (meta.isInline) {
container = process.meta.metas;
} else {
container = state.data.processes;
container = state.processes;
}
if (container) {
deleteProcessMeta(meta.id, container);
}
this.commit('makeBehaviorDirty');
},
clearProcessStack(state) {
state.processStack.splice(0);
......@@ -83,14 +95,14 @@ export const behaviorStore = {
getters: {
customProcessMap: state => {
let map = {};
for (let process of state.data.processes) {
for (let process of state.processes) {
map[process.id] = process;
}
return map;
},
metaInUse: state => targetMetaID => {
let allMetasInUse = [];
for (let process of state.data.processes) {
for (let process of state.processes) {
let usedMetas = metaInUse(process, targetMetaID);
allMetasInUse.push(...usedMetas);
/*if (usedMetas.length > 0) {
......@@ -102,7 +114,7 @@ export const behaviorStore = {
},
metaIDExists: state => id => {
let result = false;
for (let process of state.data.processes) {
for (let process of state.processes) {
if (process.id === id) {
result = true;
break;
......@@ -111,14 +123,14 @@ export const behaviorStore = {
return result;
},
behavior_getAssetByUUID: state => uuid => {
return state.data.assets.find(item => item.uuid === uuid);
return state.projectData.assets.find(item => item.uuid === uuid);
},
behavior_views: state => {
return state.data.views;
return state.projectData.views;
},
behavior_searchViewNode: state => uuid => {
if(uuid){
return searchViewNode(state.data.views, uuid);
return searchViewNode(state.projectData.views, uuid);
}
}
},
......@@ -161,7 +173,7 @@ export const behaviorStore = {
return meta;
},
searchMeta({state}, {keyword}) {
searchMeta(state.data.processes, keyword);
searchMeta(state.processes, keyword);
},
}
};
......
......@@ -5,7 +5,6 @@
*/
import {envApi} from "../../api";
import i18n from "../../i18n";
const storeKey = 'code-sync-serve-config';
......@@ -41,51 +40,6 @@ export const editorStore = {
},
},
getters: {
prefabProcessTree: state => {
return groupProcesses(state.processes, process => process.isPrefab);
},
builtinProcessTree: state => {
const builtin = groupProcesses(state.processes, process => !process.isPrefab);
let tree = [
{
name: 'builtin',
children: builtin,
}
];
const dividerProcess = {
id: 'divider',
name: 'Divider',
desc: i18n.t('Divider node desc'),//'分流节点,出口会按顺序一次执行',
};
tree.unshift(dividerProcess);
const customProcess = {
id: 'custom',
name: 'Custom',
desc: i18n.t('Custom node desc'),//'自定义节点',
};
tree.unshift(customProcess);
tree.push({
name: 'trigger',
from: 'trigger',
children: [],
});
tree.push({
name: 'custom',
from: 'custom',
children: [],
});
return tree;
},
builtinsProcessMap: state => {
let map = {};
for (let process of state.processes) {
map[process.id] = process;
}
return map;
}
},
actions: {
async updateEnv({state, commit}) {
......@@ -96,19 +50,3 @@ export const editorStore = {
},
}
};
function groupProcesses(processes, filterFunc) {
const result = [];
processes
.filter(filterFunc)
.forEach(process => {
const groupName = process.group || 'others';
let group = result.find(group => group.name === groupName);
if (!group) {
group = {name: groupName, children: []};
result.push(group);
}
group.children.push(process);
});
return result;
}
import db from "../../utils/db-storage";
import {packageApi} from "../../api";
import maxSatisfying from "semver/ranges/max-satisfying";
/**
* Created by rockyl on 2020-01-04.
*/
export const typeMapping = [
'',
'process',
'custom',
'script',
];
import db from "../../utils/db-storage";
import {packageApi} from "../../api";
import maxSatisfying from "semver/ranges/max-satisfying";
import i18n from "../../i18n";
import events from "@/global-events.js"
import {timeFormat, typeMapping} from "../../utils";
const storeName = 'packages';
export const packageStore = {
state: {
packageInfos: {
library: [],
process: [],
custom: [],
script: [],
},
packages: [],
packages: {
library: {},
process: {},
custom: {},
script: {},
},
processTree: [],
triggerProcesses: [],
customProcesses: [],
},
mutations: {
updatePackageInfos(state, packageInfos) {
for (let i = 1, li = typeMapping.length; i < li; i++) {
for (let i = 0, li = typeMapping.length; i < li; i++) {
state.packageInfos[typeMapping[i]].splice(0);
}
for (let packageInfo of packageInfos) {
packageInfo.versions = packageInfo.versions.split(',');
state.packageInfos[typeMapping[packageInfo.type]].push(packageInfo)
packageInfo.versions = packageInfo.versions.split(',').reverse();
packageInfo.remarks = packageInfo.remarks.split(',').reverse();
packageInfo.update_times = packageInfo.update_times.split(',').map(time => timeFormat(time)).reverse();
packageInfo.update_time = timeFormat(packageInfo.update_time);
state.packageInfos[typeMapping[packageInfo.type]].push(packageInfo);
}
},
updatePackage(state, packageItem) {
let group = state.packages[typeMapping[packageItem.type]];
let pid = packageItem.package_id;
group[pid] = JSON.parse(packageItem.data);
},
updateProcessTree(state) {
let processes = this.getters.processPackages;
const prefabs = groupProcesses(processes, process => process.isPrefab);
const builtins = groupProcesses(processes, process => !process.isPrefab);
const normalsTree = [];
let tree = [
{
name: 'prefab',
children: prefabs,
},
{
name: 'normal',
children: normalsTree,
}
];
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);
normalsTree.push({
name: 'builtin',
children: builtins,
});
normalsTree.push(state.triggerProcesses = {
name: 'trigger',
from: 'trigger',
children: [],
});
normalsTree.push(state.customProcesses = {
name: 'custom',
from: 'custom',
children: [],
});
state.processTree = tree;
},
updatePackages(state, packages) {
state.packages = packages ? JSON.parse(packages) : [];
updateCustomProcesses(state, processes) {
state.triggerProcesses.children = processes;
state.customProcesses.children = processes;
},
},
getters: {
getPackage: (state) => (packageId, version) => {
let packageVersions = state.packages[packageId];
if (packageVersions) {
return packageVersions[version];
}
processPackages: state => {
return state.packages[typeMapping[1]];
},
scriptPackages: state => {
return state.packages[typeMapping[2]];
},
customPackages: state => {
return state.packages[typeMapping[3]];
},
processTree: state => {
return state.processTree;
}
},
actions: {
async loadPackageInfos({state, commit}, id) {
async loadPackageInfos({state, commit}) {
const packageInfos = await packageApi.fetchPackageInfos();
commit('updatePackageInfos', packageInfos);
console.log(packageInfos);
},
async loadPackages({state, commit, dispatch}, id) {
dispatch('loadPackageInfos');
let packages = await db.get('packages', id);
commit('updatePackages', packages);
getAllPackageMetas() {
return db.getAll(storeName);
},
async applyModifyDependencies({state, commit, getters}, dependencies) {
async downloadDependencies({state, commit, getters, dispatch}, dependencies) {
let schema = {};
let packageMetas = await db.getAll(storeName);
for (let packageId in dependencies) {
let version = dependencies[packageId];
let packageData = getters.getPackage(packageId, version);
if (!packageData) {
let exists = packageExists(packageMetas, packageId, version);
if (!exists) {
schema[packageId] = version;
}
}
if (Object.keys(schema).length > 0) {
console.log(schema);
await packageApi.fetchPackages(schema);
let packages = await packageApi.fetchPackages(schema);
for (let packageItem of packages) {
let versions = await db.get(storeName, packageItem.package_id);
if (!versions) {
versions = {
id: packageItem.package_id,
type: packageItem.type,
};
}
versions[packageItem.version] = packageItem;
db.put(storeName, versions);
}
}
},
};
async applyDependencies({commit}, dependencies) {
let missings = [];
for (let packageId in dependencies) {
let version = dependencies[packageId];
let versions = await db.get(storeName, packageId);
if (versions) {
if (versions[version]) {
commit('updatePackage', versions[version]);
} else {
missings.push({
packageId,
version,
})
}
} else {
missings.push({
packageId,
version,
})
}
}
commit('updateProcessTree');
export function fillLastVersion(dependencies, packageInfos) {
for (let group in packageInfos) {
for (let packageInfo of packageInfos[group]) {
if (missings.length > 0) {
setTimeout(function () {
events.$emit('show-missing-packages', missings);
}, 500);
}
return missings;
},
async fillLastVersion({dispatch, state, getters}) {
const dependencies = getters.dependencies;
for (let group in state.packageInfos) {
for (let packageInfo of state.packageInfos[group]) {
const {package_id, versions} = packageInfo;
if (!dependencies[package_id]) {
dependencies[package_id] = maxSatisfying(versions, '*');
}
}
}
await dispatch('applyDependencies', dependencies);
}
},
};
export function packageExists(packageMetas, packageId, version) {
let exists;
let versions = packageMetas.find(item => item.id === packageId);
if (versions) {
exists = versions[version];
}
return exists;
}
function groupProcesses(processes, filterFunc) {
const result = [];
for (let pid in processes) {
let process = processes[pid];
if (filterFunc(process)) {
const groupName = process.group || 'others';
let group = result.find(group => group.name === groupName);
if (!group) {
group = {name: groupName, children: []};
result.push(group);
}
group.children.push(process);
}
}
return result;
}
......@@ -153,7 +153,7 @@ export const projectStore = {
Vue.set(localData, 'dependencies', {});
}
fillLastVersion(state.data.dependencies, state.package.packageInfos);
this.dispatch('fillLastVersion');
state.mockServeEnabled = getMockServeEnabled(id);
updateMock(localData.mock);
......@@ -481,6 +481,9 @@ export const projectStore = {
options(state) {
return state.data.options;
},
envKeys(state) {
return state.data.options.env.map(item => item.name);
},
/**
* 当前激活的组件
*/
......@@ -532,6 +535,9 @@ export const projectStore = {
getProcess: state => behavior => {
return findProcess(behavior.meta, state.data.processes);
},
dependencies(state) {
return state.data.dependencies;
},
},
actions: {
async saveToLocal({getters, commit}) {
......@@ -547,7 +553,7 @@ export const projectStore = {
return !!json;
},
async loadFromLocal({commit, dispatch}, projectID) {
await dispatch('loadPackages', projectID);
await dispatch('loadPackageInfos');
let json = await db.get(storeName, projectID);
//let json = localStorage.getItem('project-' + projectID);
if (json) {
......@@ -562,7 +568,7 @@ export const projectStore = {
commit('setDirty', false);
},
async loadFromRemote({commit, dispatch}, projectID) {
await dispatch('loadPackages', projectID);
await dispatch('loadPackageInfos');
const project = await projectApi.fetchOne(projectID);
if (project) {
dispatch('deleteLocalVersion', projectID);
......@@ -572,7 +578,7 @@ export const projectStore = {
}
},
async loadFromDataUrl({commit, dispatch}, {project, dataUrl}) {
await dispatch('loadPackages', project.id);
await dispatch('loadPackageInfos');
const projectData = await projectApi.fetchOneFromDataUrl(dataUrl);
if (projectData) {
project.data = projectData;
......@@ -590,12 +596,6 @@ export const projectStore = {
const project = await projectApi.getData(projectID);
commit('updateProject', project);
},
async resolveDependencies({state}) {
for (let key in state.data.dependencies) {
let version = state.data.dependencies[key];
}
},
/**
* 选中节点
......@@ -755,7 +755,7 @@ export const projectStore = {
savePreview({state, rootState, getters}) {
const {project} = getters;
const {processes, scripts, customs} = rootState.editor;
const packages = state.package.packages;
/*const data = {
processes, scripts, customs,
data: state.data,
......@@ -763,7 +763,7 @@ export const projectStore = {
localStorage.setItem('preview-project-' + project.id, JSON.stringify(data));
localStorage.setItem('preview-ts', Date.now().toString());*/
preprocess(project, state.data, clonePureObj(processes), clonePureObj(scripts), clonePureObj(customs))
preprocess(project, state.data, clonePureObj(packages));
},
addBehaviorDirect({state}, {behaviors, alias}) {
......
......@@ -324,7 +324,6 @@ $dock-pin-width: 9px;
}
.meta-editor-wrapper {
//height: 40vh;
display: flex;
height: 100%;
padding: 5px;
......@@ -337,15 +336,6 @@ $dock-pin-width: 9px;
.script-editor {
flex: 1;
}
.vue-codemirror {
flex: 1;
height: 0;
}
.CodeMirror {
height: 100%;
}
}
.props-editor-dialog {
......
......@@ -93,13 +93,52 @@
}
.package-manager {
.item{
.item {
border-bottom: 1px solid $--border-color-base;
padding-bottom: 5px;
.update-time{
.update-time {
margin-right: 5px;
}
.version-select {
//width: 80px;
}
}
}
.package-version-list {
padding-right: 10px;
.item {
border-bottom: 1px solid $--border-color-base;
padding: 2px;
.use-checkbox{
margin-right: 5px;
}
.version {
font-weight: bold;
float: left;
}
.update-time {
float: right;
}
}
}
.version-select-popover {
.version-label {
float: left;
}
.version-notice {
float: right;
color: $--color-warning;
font-size: 13px;
}
}
......@@ -129,13 +168,29 @@
}
}
.project-scrollbar {
height: 100%;
.project-editor {
height: 100%;
form {
height: 100%;
display: flex;
flex-direction: column;
.project-scrollbar {
.tpl-editor {
flex: 1;
.el-form-item__content {
height: 100%;
.editor {
height: 100%;
}
}
}
}
}
}
......@@ -174,6 +229,10 @@
.mock-table {
flex: 1;
}
.editor {
height: 300px;
}
}
}
......@@ -225,3 +284,16 @@
}
}
}
.missing-packages-dialog {
.wrapper {
height: 50vh;
display: flex;
flex-direction: column;
.list {
flex: 1;
height: 0;
}
}
}
/**
* Created by rockyl on 2020-02-20.
*/
import Vue from 'vue'
import {timeFormat} from "./utils";
Vue.use(function () {
Vue.prototype.$timeFormat = function(time, format){
return timeFormat(time, format);
}
});
......@@ -2,7 +2,7 @@
* Created by rockyl on 2019-12-18.
*/
const version = 4;
const version = 5;
const storeConfigs = [
{name: 'project', key: 'id'},
{name: 'mock', key: 'path'},
......
......@@ -5,6 +5,7 @@
import {Message, Loading} from "element-ui";
import i18n from '../i18n'
import generateUUID from "uuid/v4";
import moment from "moment";
/**
* 动态数据图标映射
......@@ -18,6 +19,13 @@ export const dynamicIconMapping = {
'env': 'E',
};
export const typeMapping = [
'library',
'process',
'script',
'custom',
];
/**
* 节点方案
* @type {string}
......@@ -309,3 +317,7 @@ export function getViewNodePath(node, sep = '/') {
}
return segs.join(sep)
}
export function timeFormat(time, format = 'YYYY-MM-DD HH:mm:ss'){
return moment(time).format(format)
}
......@@ -16,6 +16,7 @@
<pack-result-dialog ref="packResultDialog"/>
<mock-editor-dialog ref="mockEditorDialog"/>
<code-sync-serve-dialog ref="codeSyncServeDialog"/>
<missing-packages-dialog ref="missingPackagesDialog"/>
</div>
</template>
......@@ -37,11 +38,12 @@
import {startCodeSyncServe} from "../code-sync-serve";
import BottomBar from "./Editor/BottomBar";
import CodeSyncServeDialog from "./Editor/dialogs/CodeSyncServeDialog";
import MissingPackagesDialog from "./Editor/dialogs/MissingPackagesDialog";
export default {
name: 'Editor',
components: {
MissingPackagesDialog,
CodeSyncServeDialog,
BottomBar,
MockEditorDialog,
......@@ -82,6 +84,7 @@
events.$on('save-and-preview', () => {
this.clickMenu("preview");
});
events.$on('show-missing-packages', this.showMissingPackages);
events.$on('show-code-sync-serve-dialog', () => {
this.$refs.codeSyncServeDialog.show();
......@@ -90,7 +93,7 @@
await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
console.log(e);
});
if(this.codeSyncServeConfig.autoLaunch){
if (this.codeSyncServeConfig.autoLaunch) {
setTimeout(() => {
startCodeSyncServe(this.codeSyncServeConfig);
}, 100);
......@@ -101,7 +104,8 @@
});
},
destroyed() {
document.removeEventListener('keydown', this.onKeyPress)
document.removeEventListener('keydown', this.onKeyPress);
events.$off('show-missing-packages', this.showMissingPackages);
},
methods: {
......@@ -258,7 +262,7 @@
if (!debug) {
cancel = await this.saveProject(false);
}
if(cancel){
if (cancel) {
return;
}
const loading = this.$loading({
......@@ -313,6 +317,9 @@
window.open(previewUrl.href, 'blank');
}, 300);
},
showMissingPackages(missingPackages) {
this.$refs.missingPackagesDialog.show(missingPackages);
},
...mapActions([
'loadPackages',
'localVersionExist',
......
......@@ -20,7 +20,7 @@
<el-dropdown trigger="click" @command="handleAddScript" placement="top" size="small">
<el-button size="mini">{{$t('Add')}}</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(script, key) of scripts" :command="script.id" :key="key">{{script.name}}</el-dropdown-item>
<el-dropdown-item v-for="(script, key) of scriptPackages" :command="script.id" :key="key">{{script.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
......@@ -76,11 +76,9 @@ export default {
};
},
computed: {
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']),
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList', 'scriptPackages']),
...mapState({
scripts(state){
return state.editor.scripts;
}
}),
},
methods: {
......@@ -88,7 +86,7 @@ export default {
* 脚本预设对象选中
*/
handleAddScript(command) {
console.log('handleAddScript', command);
//console.log('handleAddScript', command);
this.$store.dispatch('addNodeScript', command);
},
/**
......@@ -140,11 +138,11 @@ export default {
return scriptTypeMap[_type].component;
},
getScriptName(id) {
let _script = this.scripts.find(script => script.id === id);
let _script = this.scriptPackages[id];
return _script ? _script.name : '';
},
getScriptOptions(id) {
let _script = this.scripts.find(script => script.id === id);
let _script = this.scriptPackages[id];
return _script ? _script.props : {};
},
/**
......
......@@ -2,10 +2,10 @@
<div class="behavior">
<split-panes>
<split-panes splitpanes-min="10" :splitpanes-size="10" horizontal>
<process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="prefabProcessTree"
<process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="processTree[0].children"
class="background full-size" splitpanes-min="20"
:splitpanes-size="20"/>
<process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="normalProcessTree"
<process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="processTree[1].children"
class="background full-size" splitpanes-min="20"
:splitpanes-size="80"/>
</split-panes>
......@@ -44,7 +44,6 @@
import events from "@/global-events.js"
import MetaSearchDialog from "./MetaSearchDialog";
export default {
name: "BehaviorEditor",
components: {MetaSearchDialog, MetaEditorDialog, PropertiesEditor, EditPath, ProcessList, Board, SplitPanes,},
......@@ -56,27 +55,18 @@
},
computed: {
processContext() {
const {builtinsProcessMap, customProcessMap} = this.$store.getters;
const {processPackages, customProcessMap} = this.$store.getters;
return [
builtinsProcessMap,
processPackages,
customProcessMap,
]
},
normalProcessTree() {
const tree = this.builtinProcessTree;
const customGroup = tree.find(item => item.name === 'custom');
customGroup.children = this.$store.state.behavior.data.processes;
const triggerGroup = tree.find(item => item.name === 'trigger');
triggerGroup.children = this.$store.state.behavior.data.processes;
return tree;
},
...mapState({
behavior: state => state.behavior.currentBehavior,
processStack: state=>state.behavior.processStack,
}),
...mapGetters([
'prefabProcessTree',
'builtinProcessTree',
'processTree',
]),
},
methods: {
......
......@@ -18,6 +18,7 @@
@down-pin="onPinDown"
@delete="onProcessNodeDelete"
@copy="onProcessNodeCopy"
@change-position="onProcessNodeMove"
@edit-meta="onEditMeta"
@dblclick="editSubProcess(process)"
@meta-modified="onProcessMetaModified"
......@@ -89,6 +90,7 @@
...mapMutations([
'deleteProcessMeta',
'setScale',
'makeBehaviorDirty',
]),
async edit(process, resolveProcess) {
this.boardOffset.x = 0;
......@@ -119,8 +121,6 @@
this.$set(this.subProcessMap, uuid, process);
} else {
console.log('节点丢失:', uuid);
}
},
showInlineChoose() {
......@@ -164,6 +164,7 @@
this.$set(this.process.meta, 'sub', {});
}
this.$set(this.process.meta.sub, data.uuid, data);
this.makeBehaviorDirty();
return data;
},
onDragOver(e) {
......@@ -215,6 +216,7 @@
this.$nextTick(() => {
events.$emit('update-dock-pin-pos');
});
this.makeBehaviorDirty();
},
onResize() {
const {x, y} = this.$el.getBoundingClientRect();
......@@ -305,12 +307,14 @@
this.addLine(this.processDrawing, this.drawState.targetUUID, this.pointDrawing, 0);
this.drawState.targetUUID = null;
this.makeBehaviorDirty();
}
},
onDeleteLine(line) {
const {prev, outputType, outputIndex, id} = line;
prev.output[outputType].splice(outputIndex, 1);
this.$delete(this.lines, id);
this.makeBehaviorDirty();
},
onProcessNodeDelete(process, meta) {
this.$delete(this.subProcessMap, process.uuid);
......@@ -341,6 +345,7 @@
});
}
}
this.makeBehaviorDirty();
},
onProcessNodeCopy(data, meta) {
if (meta.isInline) { //内联直接复制
......@@ -356,6 +361,9 @@
});
}
},
onProcessNodeMove(data){
this.makeBehaviorDirty();
},
onEditMeta(data, meta) {
this.$emit('edit-meta', meta);
},
......@@ -377,6 +385,7 @@
}
}
}
this.makeBehaviorDirty();
},
onClickProcessNode(process, uuid) {
for (let key in this.$refs) {
......
<template>
<codemirror ref="codeEditor"
:value="value"
:options="cmOptions"
@input="onChange"
@inputRead="inputRead"/>
</template>
<script>
import {codemirror} from "vue-codemirror";
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/ayu-mirage.css'
import 'codemirror/addon/edit/closebrackets.js'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/lint/lint.js'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/addon/lint/javascript-lint.js'
import 'codemirror/addon/search/searchcursor.js'
import 'codemirror/addon/search/search.js'
import 'codemirror/addon/search/jump-to-line.js'
import 'codemirror/addon/dialog/dialog.js'
import 'codemirror/addon/dialog/dialog.css'
import '../../../utils/javascript-hint.js'
export default {
name: "CodeEditor",
components: {codemirror},
data(){
return {
cmOptions: {
tabSize: 2,
styleActiveLine: true,
theme: 'ayu-mirage',
line: true,
matchBrackets: true,
autoCloseBrackets: true,
extraKeys: {
"Alt-Space": "autocomplete",
},
lineNumbers: true,
mode: {name: 'javascript', globalVars: true},
gutters: ["CodeMirror-lint-markers"],
lint: {
esversion: 6
},
keyword: {
caseInsensitive: true,
}
}
}
},
props: {
value: {
type: String,
default: '',
}
},
methods:{
inputRead(codemirror) {
if (codemirror.state.completionActive) {
return;
}
let cur = codemirror.getCursor();
let token = codemirror.getTokenAt(cur);
let string = '';
if (token.string.match(/^[.`\w@]\w*$/)) {
string = token.string;
}
if (string.length > 0) {
codemirror.showHint({ completeSingle: false });
}
},
onChange(v){
this.$emit('input', v);
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -90,22 +90,7 @@
item
}}</el-tag>
</div>
<!--<el-input v-if="meta" class="script-editor" :readonly=" !editable" type="textarea" :placeholder="$t('Code')"
v-model="meta.script"></el-input>-->
<!-- <codemirror
ref="codeEditor"
v-if="meta"
v-model="meta.script"
:options="cmOptions"
@cursorActivity="onCodeChange"
/>-->
<monaco-editor
ref="codeEditor"
v-if="meta"
:code="meta.script"
:options="monacoConfig"
/>
<!-- <code-editor v-if="meta" v-model="meta.script" /> -->
<process-script-editor v-if="meta" :meta="meta"/>
</div>
<div slot="footer" class="dialog-footer">
<div>
......@@ -132,23 +117,21 @@
</template>
<script>
import PropsEditorDialog from "./PropsEditorDialog";
import MonacoEditor from "../components/MonacoEditor";
import copy from "copy-to-clipboard";
import { clonePureObj } from "../../../utils";
import events from "../../../global-events";
import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator";
import CodeEditor from "./CodeEditor";
import PropsEditorDialog from "./PropsEditorDialog";
import copy from "copy-to-clipboard";
import {clonePureObj} from "../../../utils";
import events from "../../../global-events";
import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator";
import ProcessScriptEditor from "./ProcessScriptEditor";
const exposeVariables = ["args", "props", "target", "global", "vm", "engine", 'scope'];
const exposeVariables = ["args", "props", "target", "global", "vm", "engine", 'scope'];
export default {
name: "MetaEditorDialog",
components: {
CodeEditor,
ProcessScriptEditor,
CodeSyncIndicator,
PropsEditorDialog,
"monaco-editor": MonacoEditor
},
data() {
return {
......@@ -161,25 +144,6 @@ export default {
id: [{ required: true, trigger: "blur" }],
name: [{ required: true, trigger: "blur" }]
},
cmOptions: {
tabSize: 2,
styleActiveLine: true,
theme: "default",
line: true,
matchBrackets: true,
autoCloseBrackets: true,
extraKeys: {
"Alt-Space": "autocomplete"
},
lineNumbers: true,
mode: { name: "javascript", globalVars: true },
gutters: ["CodeMirror-lint-markers"],
lint: true
},
monacoConfig: {
language: "javascript"
}
};
},
mounted() {
......@@ -222,10 +186,8 @@ export default {
this.$t("Alert")
).catch(e => {});
} else {
this.meta.script = this.$refs.codeEditor.editor.getValue();
this.$emit("input", this.meta, isPreview);
this.visible = false;
this.meta = null;
}
} else {
return false;
......@@ -234,7 +196,6 @@ export default {
},
cancel() {
this.visible = false;
this.meta = null;
},
copyMeta() {
copy(JSON.stringify(this.meta));
......@@ -246,8 +207,7 @@ export default {
let metaStr = e.clipboardData.getData("Text");
if (metaStr) {
try {
let meta = JSON.parse(metaStr);
this.meta = meta;
this.meta = JSON.parse(metaStr);
} catch (e) {}
}
},
......
<template>
<monaco-editor
class="script-editor"
ref="editor"
v-model="meta.script"
language="javascript"
:options="monacoConfig"
@editorWillMount="editorWillMount"
/>
</template>
<script>
import MonacoEditor from "vue-monaco";
const typesUrl = [
"http://yun.duiba.com.cn/editor/zeroing/types/types.v2.d.ts",
"http://yun.duiba.com.cn/editor/zeroing/types/process-context.v8.d.ts",
];
let types;
const metaDtsTpl =
`declare function next(type: $OUTPUT_TYPES$, payload?: any);
declare interface ProcessProps {
$PROPS_TYPES$
}
declare interface EnvProps {
$ENV_PROPS$
}
`;
export default {
name: "ProcessScriptEditor",
components: {
MonacoEditor,
},
props: ['meta'],
data() {
return {
monacoConfig: {},
}
},
mounted() {
this.updateMetaDts();
},
watch: {
meta(v) {
this.updateMetaDts();
},
},
methods: {
async editorWillMount(monaco) {
this.monaco = monaco;
if (!types) {
types = (await Promise.all(typesUrl.map(async url => {
const res = await fetch(url);
return res.text();
}))).join("\n");
this.monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES6,
allowNonTsExtensions: true,
allowJs: true
});
this.monaco.languages.typescript.javascriptDefaults.addExtraLib(types);
this.updateMetaDts();
}
},
updateMetaDts() {
if (!types) {
return;
}
let meta = this.meta;
let outputTypes = meta.output.map(item => `'${item}'`).join('|');
let envKeys = this.$store.getters.envKeys;
let props = [];
for (let key in meta.props) {
let propConfig = meta.props[key];
let propType = 'string';
switch(propConfig.type){
case 'boolean':
case 'number':
propType = propConfig.type;
break;
case 'dynamic':
case 'map':
propType = 'any';
break;
case 'node':
propType = 'NodeClass';
break;
case 'enum':
propType = '{' + propConfig.enum.join(',') + '}';
break;
}
props.push(key + ':' + propType + ';');
}
let metaDts = metaDtsTpl
.replace('$OUTPUT_TYPES$', outputTypes)
.replace('$PROPS_TYPES$', props.join('\n'))
.replace('$ENV_PROPS$', envKeys.join('\n'))
console.log(metaDts);
this.monaco.languages.typescript.javascriptDefaults.addExtraLib(metaDts, 'meta.d.ts');
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div id="container"></div>
</template>
<script>
import * as monaco from "monaco-editor";
const typesUrl = [
"http://yun.duiba.com.cn/editor/zeroing/types/types.d.ts",
"http://yun.duiba.com.cn/editor/zeroing/types/process-context.v4.d.ts",
];
export default {
name: "MonacoEditor",
props: {
options: Object,
code: String
},
async mounted() {
const {options, code} = this;
const types = await Promise.all(typesUrl.map(async url => {
const res = await fetch(url);
return res.text();
}));
const defaultConfig = {
language: "javascript",
value: "",
minimap: {
enabled: false
}
};
// compiler options
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES6,
allowNonTsExtensions: true,
allowJs: true
});
// extra libraries
monaco.languages.typescript.javascriptDefaults.addExtraLib(
types.join("\n")
);
const config = Object.assign({}, defaultConfig, options, {value: code});
this.editor = monaco.editor.create(
document.getElementById("container"),
config
);
},
destroyed() {
this.editor.dispose();
}
};
</script>
<style lang="scss" scoped>
#container {
width: 100%;
height: 100%;
}
</style>
......@@ -6,8 +6,11 @@
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onSave(true)">{{$t('Save And Preview')}}</el-button>
<el-button size="mini" type="primary" @click="onSave(false)">{{$t('Save And Close')}}</el-button>
<!--<el-button size="mini" @click="onSave(true)">{{$t('Save And Preview')}}</el-button>
<el-button size="mini" type="primary" @click="onSave(false)">{{$t('Save And Close')}}</el-button>-->
<el-badge :hidden="!showBadge" is-dot>
<el-button size="mini" type="primary" @click="onSave()">{{$t('Save')}}</el-button>
</el-badge>
</div>
</div>
</el-dialog>
......@@ -30,7 +33,7 @@
computed: {
...mapState({
data: state => state.project.data,
showBadge: state => state.behavior.dirty,
}),
},
created() {
......@@ -63,20 +66,29 @@
}
},
beforeClose(done) {
if (this.$store.state.behavior.dirty) {
this.$confirm(this.$t('Save this behavior before'), this.$t('Alert'), {
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
confirmButtonText: this.$t('Confirm'),
confirmButtonText: this.$t('Save And Close'),
cancelButtonText: this.$t('Still Close'),
distinguishCancelAndClose: true,
type: 'warning'
}).then(() => {
this.onSave();
done();
}).catch((e) => {
this.$emit('cancel');
}).catch((action) => {
switch (action) {
case 'close':
break;
case 'cancel':
done();
break;
}
});
} else {
done();
}
},
onOpened() {
this.editorReady = true;
......
......@@ -6,24 +6,24 @@
fullscreen
custom-class="flex-dialog details-dialog"
>
<el-tabs v-model="activeName" class="tabs">
<el-tab-pane :label="$t('Project')" name="project">
<el-tabs v-model="activeName" class="tabs" @tab-click="onClickTab">
<el-tab-pane :label="$t('Project')" name="projectEditor">
<project-editor ref="projectEditor"/>
</el-tab-pane>
<el-tab-pane :label="$t('Env constant')" name="env">
<el-tab-pane :label="$t('Env constant')" name="envEditor">
<env-editor ref="envEditor"/>
</el-tab-pane>
<el-tab-pane :label="$t('Data mapping')" name="data-mapping">
<el-tab-pane :label="$t('Data mapping')" name="dataMappingEditor">
<data-mapping-editor ref="dataMappingEditor"/>
</el-tab-pane>
<!--<el-tab-pane :label="$t('Custom module')" name="custom">
<el-tab-pane :label="$t('Custom module')" name="customModuleEditor">
<custom-module-editor ref="customModuleEditor"/>
</el-tab-pane>-->
<el-tab-pane :label="$t('Package manager')" name="package-manager">
</el-tab-pane>
<el-tab-pane :label="$t('Package manager')" name="packageManager">
<package-manager-editor ref="packageManager"/>
</el-tab-pane>
<el-tab-pane :label="$t('Projectx config')" name="projectx">
<projectx-config ref="projectxConfig" />
<el-tab-pane :label="$t('Projectx config')" name="projectxConfig">
<projectx-config ref="projectxConfig"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
......@@ -49,7 +49,7 @@
'projectEditor',
'envEditor',
'dataMappingEditor',
//'customModuleEditor',
'customModuleEditor',
'packageManager',
'projectxConfig',
];
......@@ -58,11 +58,12 @@
name: "DetailsDialog",
components: {
PackageManagerEditor, DataMappingEditor, CustomModuleEditor, EnvEditor, ProjectEditor,
ProjectxConfig},
ProjectxConfig
},
data() {
return {
visible: false,
activeName: 'project',
activeName: 'projectEditor',
}
},
methods: {
......@@ -70,8 +71,8 @@
this.visible = true;
},
onSave() {
for (let ref of refs) {
this.$refs[ref].save();
for (let key in this.activedTabs) {
this.$refs[key].save();
}
this.visible = false;
this.modifyProjectDetails();
......@@ -80,9 +81,23 @@
this.visible = false;
},
onOpen() {
for (let ref of refs) {
this.$refs[ref].edit();
this.activedTabs = {};
this.onClickTab(this.activeName);
},
onClickTab(tab) {
let tabName;
if (typeof tab === 'string') {
tabName = tab;
} else {
tabName = tab.name;
}
let tabView = this.$refs[tabName];
if (!this.activedTabs[tab.name]) {
tabView.edit && tabView.edit();
this.activedTabs[tabName] = true;
}
tabView.active && tabView.active();
},
...mapMutations([
'modifyProjectDetails',
......
<template>
<el-dialog :title="$t('Dependencies missing')" width="50%" :visible.sync="visible"
:append-to-body="true"
custom-class="flex-dialog missing-packages-dialog"
>
<div class="wrapper">
<p v-html="$t('missingDependenciesNotice')"></p>
<div class="list">
<el-table
height="100%"
:data="missingPackages">
<el-table-column
prop="packageId"
label="ID">
</el-table-column>
<el-table-column
prop="version"
:label="$t('Version')">
</el-table-column>
</el-table>
</div>
</div>
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onConfirm" type="primary">{{$t('Confirm')}}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
export default {
name: "MissingPackagesDialog",
components: {},
data() {
return {
visible: false,
missingPackages: [],
}
},
methods: {
show(missingPackages) {
this.missingPackages = missingPackages;
this.visible = true;
},
onConfirm() {
this.visible = false;
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -14,9 +14,12 @@
<el-table class="mock-table" :data="mocks" height="100%" stripe size="mini">
<el-table-column type="expand">
<template slot-scope="props">
<codemirror ref="codeEditor"
<monaco-editor
class="editor"
v-model="props.row.data"
:options="cmOptions"/>
language="json"
:options="monacoConfig"
/>
</template>
</el-table-column>
<el-table-column
......@@ -82,30 +85,20 @@
import {mapState, mapMutations, mapActions} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import {clonePureObj} from "../../../utils";
import {codemirror} from "vue-codemirror";
import 'codemirror/addon/lint/lint.js'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/addon/lint/json-lint.js'
import MonacoEditor from "vue-monaco";
export default {
name: "MockEditorDialog",
components: {EnabledSetter, codemirror},
components: {MonacoEditor, EnabledSetter},
data() {
return {
visible: false,
mocks: [],
cmOptions: {
tabSize: 2,
styleActiveLine: true,
theme: 'default',
line: true,
matchBrackets: true,
autoCloseBrackets: true,
monacoConfig: {
lineNumbers: true,
mode: "application/json",
gutters: ["CodeMirror-lint-markers"],
lint: true
}
}
},
......
......@@ -72,7 +72,7 @@
</template>
<script>
import {mapState, mapMutations} from 'vuex'
import {mapState, mapMutations, mapGetters} from 'vuex'
import {clonePureObj} from "../../../../utils";
import AssetMappingEditorDialog from "./AssetMappingEditorDialog";
import PropsEditorDialog from "./CustomModuleEditor/PropsEditorDialog";
......@@ -92,12 +92,19 @@
...mapState({
customs: state => state.project.data.customs,
}),
...mapGetters([
'customPackages',
])
},
methods: {
edit() {
this.editData = clonePureObj(this.customs);
},
active(){
this.customMetas.splice(0);
for (let meta of this.$store.state.editor.customs) {
let packageDatas = this.customPackages;
for (let pid in packageDatas) {
let meta = packageDatas[pid];
let editData = this.editData.find(item => item.id === meta.id);
let data = editData ? editData : (editData || {});
if (!data.props) {
......
<template>
<el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<div class="mapping-list">
<el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/>
<div class="list">
<div class="list" v-if="editData">
<div class="item" v-for="(link, index) in editData">
<el-input size="mini" style="width: 30%" v-model="link.name"/>
<el-icon class="el-icon-connection"/>
......
<template>
<el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<div class="mapping-list">
<el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/>
<div class="list">
<div class="list" v-if="editData">
<div class="item" v-for="(link, index) in editData">
<el-input size="mini" style="width: 30%" v-model="link.name"/>
<el-icon class="el-icon-connection"/>
......
<template>
<div style="height: 100%;display: flex;flex-direction: column;">
<el-tabs style="flex: 1;height: 0;" class="tabs" v-model="activeName">
<el-tab-pane v-for="(group, key) in packageInfos" :label="$t('dependenciesTypes')[key]" :name="key">
<el-tab-pane v-for="(group, key, index) in packageInfos" :label="$t('dependenciesTypes')[key]" :name="key" :key="key">
<el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view package-manager">
<div class="mapping-list">
<div class="list">
<div class="item" v-for="packageInfo in group">
<div class="item" v-for="packageInfo in group" :key="packageInfo.id">
<div style="flex: 1;">
<i class="el-icon-s-cooperation"></i>
{{packageInfo.package_id}}
</div>
<el-tag class="update-time" size="mini" type="success">{{moment(packageInfo.update_time)}}</el-tag>
<el-select size="mini" v-model="editData[packageInfo.package_id]">
<el-tag class="update-time" size="mini" type="success">{{$timeFormat(packageInfo.update_time)}}</el-tag>
<el-select class="version-select" size="mini" v-model="editData[packageInfo.package_id]"
popper-class="version-select-popover">
<el-option v-for="(version, index) in packageInfo.versions"
:key="index"
:value="version"
:label="version"
></el-option>
:label="versionLabel(packageInfo.package_id, version)"
>
<span class="version-label">{{ version }}</span>
<span class="version-notice">{{ versionLabel(packageInfo.package_id, version, false) }}</span>
</el-option>
</el-select>
<el-popover
placement="left-start"
:title="$t('All versions')"
:open-delay="500"
width="250"
style="margin-left: 5px;"
trigger="click">
<div>
<el-scrollbar style="height: 200px;" wrap-class="wrap-x-hidden" view-class="package-version-list">
<div v-for="(version, index) in packageInfo.versions" :key="index" class="item">
<span class="version">v{{version}}</span>
<span class="update-time">
<i class="el-icon-time"></i>
{{packageInfo.update_times[index]}}
</span>
<br>
<span>{{packageInfo.remarks[index]}}</span>
</div>
</el-scrollbar>
</div>
<el-button slot="reference" circle icon="el-icon-files" class="micro" plain/>
</el-popover>
</div>
</div>
</div>
......@@ -26,15 +54,16 @@
<div style="margin-top: 5px;">
<el-button size="mini" @click="applyModify" type="primary">{{$t('Apply')}}</el-button>
<el-button size="mini" @click="resetModify">{{$t('Reset')}}</el-button>
<el-button size="mini" @click="refresh" type="success" plain>{{$t('Refresh')}}</el-button>
</div>
</div>
</template>
<script>
import {mapState, mapMutations, mapActions} from 'vuex'
import {clonePureObj} from "../../../../utils";
import moment from "moment";
import {mapState, mapMutations, mapActions, mapGetters} from 'vuex'
import {clonePureObj, playWaiting} from "../../../../utils";
import {packageExists} from "../../../../store/modules/package";
export default {
name: "PackageManagerEditor",
......@@ -46,34 +75,58 @@
},
computed: {
...mapState({
dependencies: state => state.project.data.dependencies,
dependencies: state => {
return state.project.data.dependencies;
},
packageInfos: state => {
console.log(state.project);
return state.project.package.packageInfos;
},
}),
...mapGetters([
'getPackage',
])
},
methods: {
moment(time) {
return moment(time).format('YYYY-MM-DD HH:mm:ss');
},
edit() {
async edit() {
this.packageMetas = await this.getAllPackageMetas();
this.editData = clonePureObj(this.dependencies);
},
save() {
async save() {
this.modifyDependencies(this.editData);
await playWaiting(this.applyDependencies(this.editData), 'Saving…');
},
async applyModify() {
await this.applyModifyDependencies(this.editData);
await playWaiting(this.downloadDependencies(this.editData), 'Downloading…');
await this.save();
this.editData = null;
this.$nextTick(async () => {
this.packageMetas = await this.getAllPackageMetas();
this.edit();
});
},
resetModify() {
this.edit();
},
async refresh() {
await playWaiting((async()=>{
await this.loadPackageInfos();
await this.fillLastVersion();
})(), 'Refreshing…');
},
versionLabel(packageId, version, withVersion = true) {
let exists = packageExists(this.packageMetas, packageId, version);
return (withVersion ? version + ' ' : '') + (!exists ? '(待下载)' : '');
},
...mapMutations([
'modifyDependencies',
]),
...mapActions([
'applyModifyDependencies',
'downloadDependencies',
'applyDependencies',
'getAllPackageMetas',
'loadPackageInfos',
'fillLastVersion',
]),
}
}
......
<template>
<div class="project-editor">
<el-scrollbar v-if="editData" class="project-scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<el-scrollbar v-if="editData" class="project-scrollbar" wrap-class="wrap-x-hidden" view-class="project-editor">
<el-form @submit.native.prevent ref="form" :model="editData" size="mini" label-position="right"
label-width="150px">
<el-form-item prop="pageTitle" :label="$t('Page title')">
......@@ -45,27 +44,20 @@
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="tpl" :label="$t('Template')">
<!-- <el-input type="textarea" v-model="options.tpl" :rows="10"/> -->
<codemirror ref="codeEditor"
<el-form-item prop="tpl" :label="$t('Template')" class="tpl-editor">
<monaco-editor
class="editor"
v-model="editData.tpl"
:options="cmOptions"
@cursorActivity="onCodeChange"
>
</codemirror>
language="html"
:options="monacoConfig"
/>
</el-form-item>
</el-form>
</el-scrollbar>
<!--<div class="operate-bar">
<el-button size="mini" @click="onReset">{{$t('Reset')}}</el-button>
<el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button>
</div>-->
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations} from 'vuex';
import {codemirror} from "vue-codemirror";
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/monokai.css'
......@@ -73,10 +65,11 @@
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css'
import {clonePureObj} from "../../../../utils";
import MonacoEditor from "vue-monaco";
export default {
name: "ProjectEditor",
components: {codemirror},
components: { MonacoEditor},
data() {
const scaleMode = this.$t('scaleMode');
const rendererType = this.$t('rendererType');
......@@ -85,16 +78,9 @@
editData: null,
scaleMode,
rendererType,
cmOptions: {
tabSize: 2,
mode: 'text/javascript',
styleActiveLine: true,
theme: 'default',
lineNumbers: true,
line: true,
matchBrackets: true,
autoCloseBrackets: true,
}
monacoConfig: {
},
}
},
computed: {
......
......@@ -16,7 +16,7 @@
<div class="project-info">
<span class="project-name">{{scope.row.name}}</span>
<el-tag size="mini" type="success">{{scope.row.operator}}</el-tag>
<el-tag size="mini" type="warning">{{moment(scope.row.update_time)}}</el-tag>
<el-tag size="mini" type="warning">{{$timeFormat(scope.row.update_time)}}</el-tag>
</div>
</template>
</el-table-column>
......@@ -96,7 +96,6 @@
import {mapState, mapActions} from 'vuex'
import CreateProjectDialog from "./Home/CreateProjectDialog";
import {playWaiting, readTextFile, saveAs, selectFile} from "../utils";
import moment from "moment";
import DuplicateProjectDialog from "./Home/DuplicateProjectDialog";
import {PROJECT_PAGE_SIZE} from "../config";
import ProjectHistoryDialog from "./Home/ProjectHistoryDialog";
......@@ -137,9 +136,6 @@
this.handleCurrentChange(1),
])
},
moment(time) {
return moment(time).format('YYYY-MM-DD HH:mm:ss');
},
showCreateProjectDialog() {
this.$refs.createProjectDialog.show();
},
......
......@@ -8,7 +8,7 @@
width="200">
<template slot-scope="scope">
<i class="el-icon-time"></i>
<span style="margin-left: 10px">{{ moment(scope.row.operator_time) }}</span>
<span style="margin-left: 10px">{{ $timeFormat(scope.row.operator_time) }}</span>
</template>
</el-table-column>
<el-table-column
......@@ -64,7 +64,6 @@
<script>
import {mapState, mapActions} from 'vuex'
import {HISTORY_PAGE_SIZE} from "../../config";
import moment from "moment";
export default {
name: "ProjectHistoryDialog",
......@@ -93,9 +92,6 @@
},
onOpen() {
},
moment(time) {
return moment(time).format('YYYY-MM-DD HH:mm:ss');
},
async handleCurrentChange(page) {
const loading = this.$loading({
......
......@@ -34,9 +34,6 @@
}
},
async mounted() {
this.codes = {};
this.urls = {};
if (!this.ts) {
this.ts = localStorage.getItem('preview-ts');
}
......@@ -94,39 +91,12 @@
return;
}
const {projectID} = this.$route.params;
const {data, codes} = await db.get('preview', projectID);
const {data, tpl} = await db.get('preview', projectID);
console.log(data);
let {options: {tpl, pageTitle, containerId}} = data;
//const dataName = projectID + "_data";
//const launchCode = `engine.launchWithWindowVariable("${dataName}");`;
const scripts = [];
for (let key in codes) {
let oldCode = this.codes[key];
let code = codes[key];
let url;
if (oldCode !== code) {
url = this.urls[key] = URL.createObjectURL(new Blob([code]));
} else {
url = this.urls[key];
}
scripts.push(newScriptEl(url));
}
scripts.push(newScriptContent('var proxy_mode=true;'));
this.codes = codes;
const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(data)]));
let {options: {pageTitle, }, } = data;
document.title = pageTitle;
tpl = tpl
.replace('$PAGE_TITLE$', pageTitle)
.replace('$CONTAINER_ID$', containerId)
.replace('$SCRIPTS$', scripts.join('\n'))
.replace('//yun.duiba.com.cn/aurora/$VERSION$-data.json', dataUrl);
const doc = this.$refs.iframe.contentDocument;
const win = this.$refs.iframe.contentWindow;
doc.write(tpl);
......@@ -172,7 +142,7 @@
bottom: 10px;
}
.proxy-iframe-wrapper{
.proxy-iframe-wrapper {
/*display: none;*/
top: 0;
position: absolute;
......
/**
* Created by rockyl on 2019-12-20.
*/
import {clonePureObj} from "../../utils";
import {clonePureObj, newScriptContent, typeMapping} from "../../utils";
import {divideCode} from "zeroing-code-divider";
import {generateLibraryScriptEl, fillTemplate, generateJsScriptEl} from "zeroing-template-fill";
import db from "../../utils/db-storage";
const storeName = 'preview';
function getPack(packs) {
return function (ids) {
return packs.filter(pack => ids.includes(pack.id))
let codesCache = {};
let urlsCache = {};
function getPackages(packages) {
return async function (schema, type) {
let ids = Object.keys(schema);
let result = ids.map(pid=>{
let packageItem = packages[typeMapping[type]][pid];
return {
data: packageItem,
};
}).filter(item=>!!item);
return result;
}
}
export async function preprocess(project, data, processes, scripts, customs) {
export async function preprocess(project, data, packages) {
let newData = clonePureObj(data);
const codes = await divideCode(newData, {
debug: true,
getProcesses: getPack(processes),
getScripts: getPack(scripts),
getCustoms: getPack(customs),
getPackages: getPackages(packages),
dependencies: data.dependencies,
});
let {options: {tpl, pageTitle, containerId}, dependencies} = data;
let scripts = [];
for (let key in codes) {
let oldCode = codesCache[key];
let code = codes[key];
let url;
if (oldCode !== code) {
url = urlsCache[key] = URL.createObjectURL(new Blob([code]));
} else {
url = urlsCache[key];
}
scripts.push(url);
}
scripts = scripts.map(item => generateJsScriptEl(item));
scripts.push(newScriptContent('var proxy_mode=true;'));
codesCache = codes;
const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(newData)]));
const {libraryScriptElMap, analyseResult} = await generateLibraryScriptEl(tpl, dependencies, getPackages(packages), '//yun.duiba.com.cn/editor/zeroing/libs/');
tpl = fillTemplate(tpl, {
pageTitle,
containerId,
scripts: scripts.join('\n'),
libraries: libraryScriptElMap,
});
tpl = tpl.replace('//yun.duiba.com.cn/aurora/$VERSION$-data.json', dataUrl);
db.set(storeName, {
id: project.id,
data: newData,
codes,
tpl,
});
localStorage.setItem('preview-ts', Date.now().toString());
}
const serverHost = 'http://10.10.95.74:7777'
const serverHost = 'http://10.10.95.74:7777';
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '//yun.duiba.com.cn/editor/zeroing/v1/' : '',
......@@ -30,9 +30,9 @@ module.exports = {
configureWebpack: {
plugins: [
new MonacoWebpackPlugin({
languages: ['javascript', 'typescript', 'json'],
languages: ['javascript', 'typescript', 'json', 'html'],
publicPath: process.env.NODE_ENV === 'production' ? "/monaco" : "",
})
]
}
}
};
......@@ -1976,7 +1976,7 @@ camelcase@^3.0.0:
resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
camelcase@^5.0.0:
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=
......@@ -2226,7 +2226,7 @@ code-point-at@^1.0.0:
resolved "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
codemirror@^5.41.0, codemirror@^5.50.0:
codemirror@^5.50.0:
version "5.50.2"
resolved "https://registry.npm.taobao.org/codemirror/download/codemirror-5.50.2.tgz#32ddfe2b50193fcf573d8141c4a31d267c92b4a3"
integrity sha1-Mt3+K1AZP89XPYFBxKMdJnyStKM=
......@@ -2961,11 +2961,6 @@ detect-node@^2.0.4:
resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=
diff-match-patch@^1.0.0:
version "1.0.4"
resolved "https://registry.npm.taobao.org/diff-match-patch/download/diff-match-patch-1.0.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdiff-match-patch%2Fdownload%2Fdiff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
integrity sha1-asS1UjdGN2HE2vDcYD64aRJHRLE=
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
......@@ -5482,17 +5477,17 @@ moment@^2.24.0:
resolved "https://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=
monaco-editor-webpack-plugin@^1.8.1:
version "1.8.1"
resolved "https://registry.npm.taobao.org/monaco-editor-webpack-plugin/download/monaco-editor-webpack-plugin-1.8.1.tgz#5701bfce16c14c51503a607726d97fd92784af26"
integrity sha1-VwG/zhbBTFFQOmB3Jtl/2SeEryY=
monaco-editor-webpack-plugin@^1.9.0:
version "1.9.0"
resolved "https://registry.npm.taobao.org/monaco-editor-webpack-plugin/download/monaco-editor-webpack-plugin-1.9.0.tgz#5b547281b9f404057dc5d8c5722390df9ac90be6"
integrity sha1-W1Rygbn0BAV9xdjFciOQ35rJC+Y=
dependencies:
loader-utils "^1.2.3"
monaco-editor@^0.19.0:
version "0.19.0"
resolved "https://registry.npm.taobao.org/monaco-editor/download/monaco-editor-0.19.0.tgz#c6e774210f3b292ff739e96f45a1cc78bf5ac2e7"
integrity sha1-xud0IQ87KS/3OelvRaHMeL9awuc=
monaco-editor@^0.20.0:
version "0.20.0"
resolved "https://registry.npm.taobao.org/monaco-editor/download/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
integrity sha1-XVAJNDpVASRCbLTZZaTSejSLTeo=
move-concurrently@^1.0.1:
version "1.0.1"
......@@ -5559,6 +5554,11 @@ nan@^2.12.1, nan@^2.13.2:
resolved "https://registry.npm.taobao.org/nan/download/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha1-eBj3IgJ7JFmobwKV1DTR/CM2xSw=
nano-assign@^1.0.0:
version "1.0.1"
resolved "https://registry.npm.taobao.org/nano-assign/download/nano-assign-1.0.1.tgz#abb1c50d0416b865fb37bbd155c5368bb54378e5"
integrity sha1-q7HFDQQWuGX7N7vRVcU2i7VDeOU=
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
......@@ -8663,14 +8663,6 @@ vue-cli-plugin-i18n@^0.6.0:
vue-i18n "^8.0.0"
vue-i18n-extract "^0.4.13"
vue-codemirror@^4.0.6:
version "4.0.6"
resolved "https://registry.npm.taobao.org/vue-codemirror/download/vue-codemirror-4.0.6.tgz#b786bb80d8d762a93aab8e46f79a81006f0437c4"
integrity sha1-t4a7gNjXYqk6q45G95qBAG8EN8Q=
dependencies:
codemirror "^5.41.0"
diff-match-patch "^1.0.0"
vue-draggable-resizable@^2.0.1:
version "2.1.0"
resolved "https://registry.npm.taobao.org/vue-draggable-resizable/download/vue-draggable-resizable-2.1.0.tgz#b590212aef3c07d040aeceda784438068170fb08"
......@@ -8709,6 +8701,13 @@ vue-loader@^15.7.0:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
"vue-monaco@http://gitlab2.dui88.com/laoqifeng/vue-monaco.git":
version "0.3.1"
resolved "http://gitlab2.dui88.com/laoqifeng/vue-monaco.git#13de23ce8ba73525cf08678227ae0c579fe2319d"
dependencies:
monaco-editor "^0.20.0"
nano-assign "^1.0.0"
vue-router@^3.0.3:
version "3.1.3"
resolved "https://registry.npm.taobao.org/vue-router/download/vue-router-3.1.3.tgz#e6b14fabc0c0ee9fda0e2cbbda74b350e28e412b"
......@@ -9168,3 +9167,9 @@ yeast@0.1.2:
"zeroing-code-divider@http://gitlab2.dui88.com/laoqifeng/zeroing-code-divider.git":
version "1.0.1"
resolved "http://gitlab2.dui88.com/laoqifeng/zeroing-code-divider.git#b2b6d191972fd597388795f249a09071db8f33eb"
"zeroing-template-fill@http://gitlab2.dui88.com/laoqifeng/zeroing-template-fill.git":
version "1.0.0"
resolved "http://gitlab2.dui88.com/laoqifeng/zeroing-template-fill.git#574fc720889a52714ec437fc5cc6dcbc002083b3"
dependencies:
camelcase "^5.3.1"
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