Commit ecdac185 authored by 任建锋's avatar 任建锋

Merge branch 'dev' of http://gitlab2.dui88.com/laoqifeng/zeroing-editor into dev

parents 8fc7ba69 53645390
......@@ -2,8 +2,8 @@
* Created by rockyl on 2019-11-25.
*/
var mergeFlagReg = /__m$/;
var excludeFlagReg = /__e$/;
var mergeFlagReg = /__m/;
var excludeFlagReg = /__e/;
var extName = '.psd';
var oldDocument = app.activeDocument;
......@@ -15,7 +15,12 @@ var document = oldDocument.duplicate(oldDocument.name.replace(extName, '') + '-
function traverse(layer, callback) {
if (layer.layers) {
for (var i = 0, li = layer.layers.length; i < li; i++) {
var childLayer = layer.layers[i];
var childLayer;
try {
childLayer = layer.layers[i];
}catch (e) {
alert('图层[' + layer.name + ']的第' + i + '个子图层存在问题,请先处理掉');
}
var action = callback(childLayer);
switch (action) {
case 0:
......
......@@ -7,9 +7,9 @@
import { fetchApi } from "./common"
import { getCookie } from './utils'
export async function fetchAll(currentPage, pageSize, onlyMine) {
export async function fetchAll(keyword, currentPage, pageSize, onlyMine) {
return await fetchApi('/api/project/query', {
params: { currentPage, pageSize, isAll: onlyMine ? 0 : 1 },
params: {name: keyword, currentPage, pageSize, isAll: onlyMine ? 0 : 1 },
errMessage: 'Failed to fetch projects',
})
}
......
......@@ -16,6 +16,7 @@
</style>
<script>
import events from "@/global-events.js"
import {assetScheme} from "../../../utils";
export default {
props: {
......@@ -35,7 +36,7 @@
drop(e) {
if (this.$store.state.project.dragUUID) {
console.log('native drop', this.$store.state);
this.swvalue = `asset://${this.$store.state.project.dragUUID}`
this.swvalue = assetScheme + this.$store.state.project.dragUUID
}
},
dragOver(e) {
......@@ -54,7 +55,7 @@
computed: {
url: function () {
if (this.swvalue) {
if (this.swvalue.indexOf('asset://') > -1) {
if (this.swvalue.indexOf(assetScheme) > -1) {
let uuid = this.swvalue.split('//')[1];
let _ass = this.$store.state.project.data.assets.find(a => a.uuid === uuid);
return _ass ? _ass.url : '';
......
......@@ -7,7 +7,7 @@ if (process.env.NODE_ENV === 'development') {
//API_HOST = '//10.10.95.74:7777';
//API_HOST = '//192.168.1.16:7777';
//API_HOST = '//10.10.92.100:7777';
//API_HOST = '//192.168.0.106:7777';
//API_HOST = '//192.168.0.105:7777';
//API_HOST = '//localhost:3002';
API_HOST = window.__data.apiHost;
//API_HOST = '';
......@@ -23,7 +23,7 @@ export const SSO_VERIFY_PAGE_URL = '/sso/logout';
export const DOCK_POINT_OFFSET = 4;
export const PROJECT_PAGE_SIZE = 20;
export const PROJECT_PAGE_SIZE = 10;
export const HISTORY_PAGE_SIZE = 20;
//文件类型图标 t表示展示缩略图
......
......@@ -23,6 +23,7 @@
"Apply": "应用",
"Props": "属性",
"Behavior": "行为",
"Search": "搜索",
"Only mine": "仅我的",
"Add": "添加",
"Delete": "删除",
......@@ -81,7 +82,8 @@
"Saving": "保存中…",
"Divider": "分流节点",
"Custom": "自定义节点",
"Custom event": "自定义事件",
"Custom global event": "自定义全局事件",
"Custom private event": "自定义私有事件",
"Entry": "入口",
"Packing": "打包",
"Type": "类型",
......@@ -109,6 +111,8 @@
"Trigger once": "触发一次",
"Meta Editor": "过程元配置",
"Env editor": "环境编辑器",
"Inline": "内联",
"Common": "通用",
"As inline": "作为内联",
"Project": "项目",
"Check template code": "查看模板代码",
......@@ -158,9 +162,11 @@
"Remote Version": "远程版本",
"Confirm to exit the editor": "确定退出编辑器吗?",
"Confirm to publish": "确定发布吗?",
"Are you sure to delete this process?": "确定删除这对应的过程吗",
"Are you sure to delete it's process": "确定删除这对应的过程吗",
"Are you sure to delete this asset": "确定删除这个素材吗",
"Are you sure to delete this behavior?": "确定删除这个的行为吗",
"Are you sure to delete this process?": "确定删除这个的过程吗",
"Are you sure to delete it's process?": "确定删除行为对应的过程吗",
"Are you sure to delete this asset?": "确定删除这个素材吗",
"Are you sure to combine those assets?": "确定合并这些素材吗",
"Are you sure to delete all assets": "确定删除全部素材吗",
"Are you sure to delete this item": "确定删除这一项吗",
"Rename asset": "重命名素材",
......@@ -183,7 +189,7 @@
"Import view success": "视图导入成功",
"Input projectx id": "请输入{envName}星速台项目ID",
"Save template to projectx": "是否保存皮肤到星速台",
"All versions": "全部版本",
"All versions": "全部版本",
"Dependencies missing": "依赖缺失",
"missingDependenciesNotice": "<i class=\"el-icon-warning\"></i>依赖缺失,请到【<span style=\"font-weight: bold,\">详情>包管理</span>】进行安装",
"Pack manager": "打包管理",
......@@ -196,6 +202,7 @@
"Skin html required": "皮肤代码必填",
"Skin name": "皮肤名",
"Skin html": "皮肤代码",
"Click save will overwrite and apply immediately": "即将覆盖【{name} | {skin}】并立刻生效,确定吗?",
"Copy skin success": "复制皮肤成功",
"Copy url success": "复制链接成功",
"Copy skin": "复制皮肤",
......@@ -205,7 +212,7 @@
"Index page exists": "已存在首页",
"Please config projectID": "请先配置{env}环境下的projectId",
"Online ticket is invalid": "线上tickct失效,请联系管理员修改",
"Are you sure to translate to normal process?": "你确定将此转化为通用过程吗?",
"Are you sure to transform process?": "你确定将此转化为{inlineType}过程吗?",
"Input custom process name": "请输入自定义过程名称",
"Invalid name": "无效名称",
"eventGroup": {
......@@ -344,5 +351,10 @@
"process": "过程库",
"script": "脚本库",
"custom": "模块库"
},
"assetItemMenu": {
"rename": "重命名",
"replace": "替换",
"combine": "合并"
}
}
\ No newline at end of file
......@@ -37,6 +37,7 @@ export default new Vuex.Store({
'addAsset',
'deleteAsset',
'deleteAllAssets',
'combineAssets',
'modifyAsset',
'importView',
'importAssets',
......
......@@ -92,14 +92,44 @@ export const behaviorStore = {
}
state.drawState.boardScale = Math.max(Math.min(4, scale), 0.1);
},
translateToNormal(state, {meta, parentMeta}) {
meta.isInline = false;
let index = parentMeta.metas.indexOf(meta);
switchProcessInlineType(state, {process, parentMeta}) {
let newMeta = process.meta;
const {isInline} = newMeta;
let oldUUID = newMeta.id;
let newUUID = generateUUID();
if (isInline) {
newMeta.id = newUUID;
newMeta.isInline = false;
let index = parentMeta.metas.indexOf(newMeta);
parentMeta.metas.splice(index, 1);
state.processes.push(meta);
state.processes.push(newMeta);
for (let key in parentMeta.sub) {
let subProcess = parentMeta.sub[key];
if (subProcess.meta === oldUUID) {
subProcess.meta = newUUID;
}
}
} else {
newMeta = clonePureObj(newMeta);
newMeta.id = newUUID;
newMeta.isInline = true;
Vue.set(parentMeta, 'metas', []);
parentMeta.metas.push(newMeta);
process.metaID = newUUID;
}
for (let key in parentMeta.sub) {
let subProcess = parentMeta.sub[key];
console.log(subProcess.meta);
}
this.commit('makeBehaviorDirty');
},
},
getters: {
customProcessMap: state => {
......
......@@ -7,7 +7,7 @@ import {editorApi, projectApi} from "../../api"
import path from "path"
import generateUUID from "uuid/v4"
import {flattenViews, getCmpByUUID, getCmpProps} from '../../utils/common'
import {clonePureObj, findProcess, getMockServeEnabled, saveAs, traverseViewNode} from "../../utils"
import {assetScheme, clonePureObj, findProcess, getMockServeEnabled, saveAs, traverseViewNode} from "../../utils"
import {template} from "../../template"
import events from "@/global-events"
import {packImages} from "../../utils/sheet-pack"
......@@ -445,6 +445,26 @@ export const projectStore = {
importAssets(state, assets) {
state.data.assets.push(...assets);
},
combineAssets(state, {targetAsset, selectedAssets}) {
//todo 需要遍历所有节点查找使用并替换
const assets = state.data.assets;
let targetAssetUrl = assetScheme + targetAsset.uuid;
let replaceAssetUrls = [];
for (let asset of selectedAssets) {
if (asset !== targetAsset) {
replaceAssetUrls.push(assetScheme + asset.uuid);
assets.splice(assets.indexOf(asset), 1);
}
}
traverseViewNode(state.data.views, function (node) {
let properties = node.properties;
for (let key in properties) {
if (properties[key] && replaceAssetUrls.includes(properties[key])) {
properties[key] = targetAssetUrl;
}
}
});
},
addAsset(state, {url, file}) {
const ext = path.extname(file.name);
state.data.assets.push({
......@@ -584,6 +604,9 @@ export const projectStore = {
let index = entries.indexOf(behavior.meta);
if (index >= 0) {
let path = paths.splice(index, 1, null)[0];
if(!path){
continue;
}
path[0] = {
process: behavior,
metaName: path[0].name,
......@@ -706,7 +729,7 @@ export const projectStore = {
// 设置image类型节点的原图高宽度
if (!_props.imageWidth || !_props.imageHeight) {
let _url = _props.source; //_source.value;
if (_url.indexOf('asset://') === 0) {
if (_url.indexOf(assetScheme) === 0) {
let uuid = _url.split('//')[1];
let asset = state.data.assets.find(a => a.uuid === uuid);
_url = asset ? asset.url : _url;
......
......@@ -32,8 +32,8 @@ export const projectsStore = {
},
},
actions: {
async fetchProjects({commit, state}, {currentPage, pageSize, onlyMine}) {
const data = await projectApi.fetchAll(currentPage, pageSize, onlyMine);
async fetchProjects({commit, state}, {keyword, currentPage, pageSize, onlyMine}) {
const data = await projectApi.fetchAll(keyword, currentPage, pageSize, onlyMine);
commit('updateProjects', data);
},
async fetchProject({commit}, projectId) {
......
......@@ -112,13 +112,9 @@
bottom: 1px;
display: flex;
.el-button + .el-button{
.delete-button{
margin-left: 2px;
}
.el-button {
padding: 2px;
}
}
}
......
......@@ -128,6 +128,10 @@
.update-time {
float: right;
}
.remark {
font-size: 12px;
}
}
}
......@@ -239,12 +243,23 @@
.px-skin-editor-dialog {
.wrapper {
padding: 10px;
height: 100%;
display: flex;
flex-direction: column;
.env-select {
align-self: flex-end;
.header{
display: flex;
align-items: center;
.env-select{
}
.px-project-name{
margin-left: 10px;
font-weight: bold;
color: $--color-danger;
}
}
.operate-wrapper > :not(*:first-child) {
......@@ -286,6 +301,32 @@
}
}
.dialog-footer{
.save-button{
margin-left: 10px;
}
}
}
.px-publish-view {
display: flex;
flex-direction: column;
.px-project-name{
font-weight: bold;
color: $--color-danger;
}
.operate-bar{
display: flex;
}
.name {
display: inline-block;
width: 200px;
}
}
.meta-search-dialog {
......
......@@ -25,8 +25,21 @@
.project-list {
flex: 1;
display: flex;
flex-direction: column;
margin-bottom: 10px;
height: 0;
.filter-bar{
align-self: flex-end;
display: flex;
align-items: center;
}
.table{
flex: 1;
}
}
.project-info {
......@@ -40,6 +53,7 @@
flex: 1;
font-size: 30px;
font-weight: bold;
line-height: 42px;
}
.project-detail {
......@@ -47,6 +61,7 @@
}
.bottom-bar {
height: 32px;
display: flex;
justify-content: space-between;
}
......
......@@ -126,7 +126,7 @@
}
.edit-button {
margin-left: 3px;
}
.delete-button {
......
.zero-playground-body-center{
position: relative;
width: 750px;
height: 1206px;
margin: 10px auto;
height: 1200px;
// max-height: 1200px;
background-color: transparent;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
......
import _ from 'lodash';
import properties from './properties';
import {assetScheme} from "./index";
// 属性的计算方法
const propsComputeRules = {
......@@ -199,7 +200,7 @@ export const styles = {
let resultObj = {};
_.forIn(obj, (value, key) => {
if (key === 'source' && value.indexOf('asset://') === 0) {
if (key === 'source' && value.indexOf(assetScheme) === 0) {
let uuid = value.split('//')[1];
let asset = project.data.assets.find(a => a.uuid === uuid);
value = asset ? asset.url : '';
......@@ -276,6 +277,10 @@ export const styles = {
// 如果是label类型,把fillColor转换为color
cmpSelfProps.color = cmpSelfProps.fillColor;
delete cmpSelfProps.fillColor;
if (cmpSelfProps.italic) { //斜体
delete cmpSelfProps.italic;
cmpSelfProps.fontStyle = 'italic';
}
if (!onlyOpera) {
if (cmpSelfProps.lineType === 'single') {
// word-break: keep-all;white-space: nowrap;
......@@ -332,7 +337,7 @@ export function getCmpProps(type) {
inherits.unshift(_.cloneDeep(typeProps));
}
let result = Object.assign({}, ...inherits);
cmpPropsCache[type] = result;
cmpProps = cmpPropsCache[type] = result;
delete result.base;
delete result.groupName;
}
......
......@@ -37,6 +37,7 @@ export const pxHostMapping = {
* @type {string}
*/
export const nodeScheme = 'node://';
export const assetScheme = 'asset://';
/**
* 弹出错误消息
......
......@@ -156,6 +156,14 @@ export default {
},
value: false,
},
italic: {
title: '斜体',
type: 'switch',
props: {
width: 40
},
value: false,
},
fillColor: {
title: '颜色',
type: 'colorPicker',
......@@ -417,8 +425,8 @@ export default {
type: 'inputNumber',
value: 0,
},
itemCol: {
title: '列数',
cols: {
title: '列数',
type: 'inputNumber',
value: 1,
},
......
......@@ -3,14 +3,16 @@
<slot name="first"></slot>
<file-item v-for="(asset, index) in assets" :class="{select: isSelected(index)}" :editable="editable" :data="asset"
:key="index" @show-file-details="showFileDetails(asset)"
@click="onClickItem(asset)"
:combinable="combinable"
@click="onClickItem(asset, $event)"
@delete="onDeleteItem(asset)"
@combine="onCombineAssets"
/>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
import {mapGetters, mapMutations} from 'vuex';
import FileItem from "./FileItem";
export default {
......@@ -28,6 +30,16 @@
}
},
computed: {
selectedAssets() {
let assets = [];
for(let index of this.selectedIndices){
assets.push(this.assets[index]);
}
return assets;
},
combinable(){
return this.selectedIndices.length > 1
},
...mapGetters([
'assets',
])
......@@ -36,25 +48,68 @@
showFileDetails(asset) {
this.$emit('show-file-details', asset);
},
onClickItem(asset) {
onClickItem(asset, event) {
this.$emit('click-item', asset);
if (event.altKey) {
if (this.isSelected(asset)) {
this.unselectItem(asset);
} else {
this.selectItem(asset, false);
}
} else {
this.selectItem(asset);
}
},
onDeleteItem(asset) {
if (this.isSelected(this.assets.indexOf(asset))) {
if (this.isSelected(asset)) {
this.selectItem();
this.$emit('click-item', null);
}
},
selectItem(asset) {
onCombineAssets(targetAsset) {
if (this.selectedIndices.length <= 1) {
return;
}
this.$confirm(this.$t('Are you sure to combine those assets?'), this.$t('Alert'), {
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning'
}).then(() => {
this.combineAssets({
targetAsset,
selectedAssets: this.selectedAssets
});
this.selectItem(targetAsset);
}).catch((e) => {
});
},
selectItem(asset, unselectAll = true) {
if (unselectAll) {
this.selectedIndices.splice(0);
}
if (asset) {
this.selectedIndices.push(this.assets.indexOf(asset));
}
},
isSelected(index) {
return this.selectedIndices.includes(index);
unselectItem(asset) {
let sIndex = this.assets.indexOf(asset);
this.selectedIndices.splice(this.selectedIndices.indexOf(sIndex), 1);
},
isSelected(item) {
let index;
if (typeof item === 'object') {
index = this.assets.indexOf(item);
} else {
index = item;
}
return this.selectedIndices.includes(index);
},
...mapMutations(['combineAssets']),
}
}
</script>
......
......@@ -7,11 +7,32 @@
class="thumbnail alpha-image-background" :src="thumbnailUrl"
alt="thumb" @dblclick="onDbclick()">
<div v-if="editable" class="operate-bar">
<el-button circle size="mini" type="success" icon="icon-upload" @dblclick.native.stop
@click="onClickReplace"/>
<el-button circle size="mini" type="success" icon="el-icon-edit" @dblclick.native.stop @click="onClickEdit"/>
<el-button circle size="mini" type="danger" icon="el-icon-delete" @dblclick.native.stop
@click="onClickDelete"/>
<!--<el-button class="micro" circle plain size="mini" type="success" icon="icon-upload" @dblclick.native.stop
@click="onClickReplace"/>-->
<!--<el-button class="micro" circle plain size="mini" type="success" icon="el-icon-edit" @dblclick.native.stop @click="onClickEdit"/>-->
<el-dropdown size="mini" trigger="click" placement="top" @command="onMoreMenu">
<el-button circle size="mini" class="micro" type="success" icon="el-icon-more" @click.stop/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item, key) in assetItemMenu"
:command="key"
:key="key"
:disabled="key === 'combine' && !combinable"
>{{item}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-popconfirm class="delete-button" :title="$t('Are you sure to delete this asset?')"
@onConfirm="onClickDelete"
placement="top">
<el-button
slot="reference"
class="micro" circle size="mini"
type="danger"
icon="el-icon-delete"
@click.stop
/>
</el-popconfirm>
</div>
</div>
<div class="name">
......@@ -31,9 +52,12 @@
props: {
data: {type: Object},
editable: {type: Boolean, default: false},
combinable: {type: Boolean, default: false}
},
data() {
return {}
return {
assetItemMenu: this.$t('assetItemMenu'),
}
},
watch: {},
computed: {
......@@ -56,7 +80,7 @@
this.$emit('show-file-details', this.data);
},
onClickDelete() {
this.$confirm(this.$t('Are you sure to delete this asset'), this.$t('Alert'), {
/*this.$confirm(this.$t('Are you sure to delete this asset'), this.$t('Alert'), {
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
......@@ -67,9 +91,24 @@
this.$emit('delete', this.data);
this.deleteAsset(this.data.uuid);
}).catch((e) => {
});
});*/
this.$emit('delete', this.data);
this.deleteAsset(this.data.uuid);
},
onMoreMenu(command) {
switch (command) {
case 'rename':
this.editName();
break;
case 'replace':
this.replace();
break;
case 'combine':
this.$emit('combine', this.data);
break;
}
},
onClickEdit() {
editName() {
this.$prompt(this.$t('Input asset name'), this.$t('Rename asset'), {
inputValue: this.data.name,
confirmButtonText: this.$t('Confirm'),
......@@ -83,7 +122,7 @@
}).catch(() => {
});
},
onClickReplace() {
replace() {
selectFile((files) => {
let file = files[0];
this.replaceAsset({
......
......@@ -6,7 +6,8 @@
<el-dropdown-item :disabled="!!activeComponent.events[key]" v-for="(item, key) in builtinEvents" :command="key"
:key="key">{{item}}
</el-dropdown-item>
<el-dropdown-item divided command="custom">{{$t('Custom event')}}</el-dropdown-item>
<el-dropdown-item divided command="custom-global">{{$t('Custom global event')}}</el-dropdown-item>
<el-dropdown-item command="custom-private">{{$t('Custom private event')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="trigger-list">
......@@ -14,6 +15,7 @@
<div class="top-bar">
<span class="el-icon-caret-right el-tree-node__expand-icon expanded-arrow"
:class="{expanded: !trigger.collapse}"></span>
<el-icon v-if="trigger.custom" :name="trigger.private ? 's-opportunity' : 's-home'"></el-icon>
<span class="name" @click="toggleCollapse(trigger)">
{{$t('events')[name] || name}}({{trigger.behaviors.length}})
</span>
......@@ -34,9 +36,13 @@
<div v-for="(behavior, index) in trigger.behaviors" class="behavior-item">
<enabled-setter :target="behavior"/>
<span v-if="!getBehavior(behavior)" class="name-field missing-behavior">{{$t('Missing behavior')}}</span>
<input v-else class="name-field name-input" type="text" v-model="getBehavior(behavior).name" @change="onBehaviorNameChange"></input>
<el-button icon="el-icon-minus" class="delete-button" type="danger" plain circle size="mini"
@click="deleteBehavior(index, trigger.behaviors)"/>
<input v-else class="name-field name-input" type="text" v-model="getBehavior(behavior).name"
@change="onBehaviorNameChange"></input>
<el-popconfirm class="delete-button" @onConfirm="deleteBehavior(index, trigger.behaviors)"
:title="$t('Are you sure to delete this behavior?')">
<el-button slot="reference" icon="el-icon-minus" type="danger" plain circle size="mini"/>
</el-popconfirm>
<el-button icon="el-icon-edit" class="edit-button" type="primary" plain circle size="mini"
@click="editBehavior(behavior, trigger.behaviors)"/>
</div>
......@@ -84,9 +90,17 @@
},
addTrigger(command) {
let trigger = {behaviors: []};
if (command === 'custom') {
switch (command) {
case 'custom-global':
case 'custom-private':
trigger.custom = true;
break;
}
if (command === 'custom-private') {
trigger.private = true;
}
this.addBehavior(command, trigger.behaviors);
this.$set(this.activeComponent.events, command, trigger);
},
......@@ -149,34 +163,28 @@
editBehavior(behavior, behaviors) {
events.$emit('edit-behavior', [{process: behavior}]);
},
onBehaviorNameChange(){
onBehaviorNameChange() {
this.makeProjectDirty();
},
async deleteBehavior(index, behaviors) {
let deleteMeta = false;
let close;
await this.$confirm(this.$t('Are you sure to delete it\'s process'), this.$t('Alert'), {
await this.$confirm(this.$t('Are you sure to delete it\'s process?'), this.$t('Alert'), {
confirmButtonText: this.$t('Delete'),
cancelButtonText: this.$t('Not delete'),
distinguishCancelAndClose: true,
type: 'warning'
}).then(() => {
deleteMeta = true;
this.makeProjectDirty();
}).catch(action => {
if(action === 'close'){
close = true;
}
});
if(!close){
this.deleteBehaviorDirect({
behaviors,
index,
deleteMeta,
})
}
},
...mapActions([
'modifyActiveView',
......
<template>
<div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-form ref="form" size="mini" :model="form" label-width="80px" @submit.native.prevent>
<el-form ref="form" size="mini" :model="form" label-width="100px" @submit.native.prevent>
<el-collapse accordion v-if="activeComponent.scripts && activeComponent.scripts.length">
<template v-for="(script, index) in activeComponent.scripts">
<el-collapse-item :title="getScriptName(script.script)" :key="script + index">
......
......@@ -39,6 +39,7 @@
:allow-drop="allowDrop"
:filter-node-method="filterNodeMethod"
@node-click="handleNodeClick"
@node-drop="onNodeDrop"
>
<div slot-scope="{ node, data }" class="tree-node">
<div class="node-name">
......@@ -209,6 +210,9 @@
return dropNode.parent.parent || type === 'inner';
}
},
onNodeDrop(){
this.makeProjectDirty();
},
/**
* 点击左侧视图列表
*/
......@@ -319,7 +323,7 @@
break;
}
},
...mapMutations(['copyNode', 'pasteNode', 'deleteNode', 'addNode']),
...mapMutations(['copyNode', 'pasteNode', 'deleteNode', 'addNode', 'makeProjectDirty']),
...mapActions(['exportView', 'importView', 'importPsd'])
}
};
......
......@@ -24,7 +24,7 @@
<board ref="board"
@select-process-node="onSelectProcessNode"
@edit-process="editProcess"
@translate-to-normal="onTranslateToNormal"
@transform="onClickTransform"
@edit-meta="onEditMeta"/>
</div>
<div class="properties background full-size" splitpanes-min="20" :splitpanes-size="20">
......@@ -153,10 +153,12 @@
}
this.$refs.board.updateProcessNode(meta.id);
},
onTranslateToNormal(meta, parentMeta) {
this.$confirm(this.$t('Are you sure to translate to normal process?'), this.$t('Alert'))
onClickTransform(process, parentMeta) {
const {isInline} = process.meta;
const inlineType = this.$t(isInline ? 'Common' : 'Inline');
this.$confirm(this.$t('Are you sure to transform process?', {inlineType}), this.$t('Alert'))
.then(() => {
this.translateToNormal({meta, parentMeta});
this.switchProcessInlineType({process, parentMeta});
}).catch(e => {
})
},
......@@ -169,7 +171,7 @@
'pushProcessStack',
'popProcessStack',
'setScale',
'translateToNormal',
'switchProcessInlineType',
]),
...mapGetters([
'metaInUse',
......
......@@ -22,7 +22,7 @@
@edit-meta="onEditMeta"
@dblclick="editSubProcess(process)"
@meta-modified="onProcessMetaModified"
@translate-to-normal="onTranslateToNormal"
@transform="onClickTransform"
/>
</g>
</g>
......@@ -399,8 +399,8 @@
onEditMeta(meta, parentMeta) {
this.$emit('edit-meta', meta, parentMeta);
},
onTranslateToNormal(meta) {
this.$emit('translate-to-normal', meta, this.process.meta);
onClickTransform(process) {
this.$emit('transform', process, this.process.meta);
},
editSubProcess(process) {
if (!process.meta.isDivider && this.editable && (process.meta.type !== 'builtin' || process.meta.sub && Object.keys(process.meta.sub).length > 0)) {
......
......@@ -7,7 +7,11 @@ export default class Process {
this._resolveProcess = resolveProcess;
this._parent = parent;
this._data = data;
this.meta = typeof data.meta === 'string' ? this.resolveMeta(data.meta) : data.meta;
if (typeof data.meta === 'string') {
this.metaID = data.meta;
} else {
this.meta = data.meta;
}
}
get data() {
......@@ -22,6 +26,11 @@ export default class Process {
return this._data.uuid;
}
set metaID(id) {
this._data.meta = id;
this.meta = this.resolveMeta(id);
}
resolveMeta(id) {
let meta = this.meta && this.meta.metas ? this.meta.metas.find(meta => meta.id === id) : null;
if (!meta && this._parent) {
......
......@@ -4,7 +4,7 @@
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave" @click="onClick" @dblclick="onDblclick">
<div class="top-bar" v-if="meta.id !== 'entry' && editable">
<el-link icon="el-icon-magic-stick" :underline="false" v-if="meta.isInline" @mousedown.stop.prevent @click.stop="onClickTranslate"/>
<el-link icon="el-icon-magic-stick" :underline="false" v-if="meta.type !== 'builtin'" @mousedown.stop.prevent @click.stop="onClickTransform"/>
<el-link icon="el-icon-delete" :underline="false" @mousedown.stop.prevent @click.stop="onClickDelete"/>
<el-link icon="el-icon-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider"
@mousedown.stop.prevent @click.stop="onClickEdit"/>
......@@ -249,8 +249,8 @@
this.$emit('down-pin', e, this.data, pin);
}
},
onClickTranslate() {
this.$emit('translate-to-normal', this.meta);
onClickTransform() {
this.$emit('transform', this.process);
},
onClickDelete() {
this.$confirm(this.$t('Are you sure to delete this process?'))
......
<template>
<div class="config">
<div class="px-publish-view">
<span class="px-project-name">
{{pxProjectName}}
</span>
<div class="operate-bar">
<el-select size="small" v-model="env" placeholder="请选择环境" @change="changeEnv">
<el-option v-for="(item, key) in pxEnvs" :key="key" :label="item" :value="key"></el-option>
</el-select>
......@@ -14,7 +18,7 @@
clearable
>
<el-option
v-for="item in skinList"
v-for="item in skins"
:key="item.id"
:label="`${item.type !== 0 ? item.name : '首页'}(${item.id})`"
:value="item.id"
......@@ -26,8 +30,12 @@
</el-select>
<el-input v-model="name" size="small" class="name" placeholder="请输入皮肤名称"></el-input>
</div>&nbsp;
<el-button type="primary" size="small" @click="clickSave">保存</el-button>
<el-button v-if="skinId" type="primary" size="small" @click="getUrl">获取链接</el-button>
<el-popconfirm v-if="skinId" class="save-button" @onConfirm="clickSave" placement="top"
:title="$t('Click save will overwrite and apply immediately', {name: this.pxProjectName, skin: skinName})">
<el-button slot="reference" type="primary" size="small">{{ $t("Save") }}</el-button>
</el-popconfirm>
<el-button v-if="skinId" size="small" @click="getUrl">获取链接</el-button>
</div>
</div>
</template>
......@@ -59,12 +67,16 @@
tplType: 0,
skinId: "",
skinList: [],
pxProjectName: "",
skins: [],
pxPid: "",
name: ""
};
},
computed: {
skinName(){
return this.skins.find(skin => skin.id === this.skinId).name;
},
...mapGetters(["options"])
},
methods: {
......@@ -90,7 +102,7 @@
if (!pxPid) {
this.$message({
message: `请先配置${env}环境下的projectId`,
message: this.$t('Please config projectID', {env}),
type: "error"
});
return;
......@@ -98,7 +110,8 @@
try {
const data = await getProjectSkins(pxPid, env);
if (data.success !== false) {
this.skinList = data;
this.pxProjectName = data.name;
this.skins = data.skins;
} else {
// 如果是测试环境,ticket过期,则重新获取ticket
if (env === "test" && data.notLogin) {
......@@ -108,26 +121,28 @@
} else if (env === "prod" && data.notLogin) {
localStorage.setItem("prod_ticket", "");
this.$message({
message: "线上tickct失效,请联系管理员修改",
message: this.$t('Online ticket is invalid'),
type: "info"
});
this.skinList = [];
this.pxProjectName = '';
this.skins = [];
} else {
this.$message({
message: data.message,
type: "error"
});
this.skinList = [];
this.pxProjectName = '';
this.skins = [];
}
}
} catch (e) {
this.skinList = [];
this.pxProjectName = '';
this.skins = [];
throw new Error(e.message);
}
},
hasIndex() {
const {skinList} = this;
return skinList.some(v => v.type === "1");
return this.skins.some(v => v.type === "1");
},
async clickSave() {
const {
......@@ -138,7 +153,6 @@
pxPid,
tpl,
name,
skinList
} = this;
if (operate === 1 && !skinId) {
this.$message({message: "请选择修改的皮肤", type: "warning"});
......@@ -182,9 +196,9 @@
},
/** 获取访问链接 */
getUrl() {
const {env, skinId, pxPid, skinList} = this;
const {env, skinId, pxPid, skins} = this;
let type = 1;
skinList.forEach(skin => {
skins.forEach(skin => {
if (skin.id === skinId) {
type = skin.type;
}
......@@ -206,9 +220,9 @@
}
},
/*getTpl(id) {
const {skinList} = this;
const {skins} = this;
let tpl = "";
skinList.forEach(skin => {
skins.forEach(skin => {
if (skin.id === id) {
tpl = skin.html;
}
......@@ -219,12 +233,5 @@
};
</script>
<style lang="scss">
.config {
display: flex;
.name {
display: inline-block;
width: 200px;
}
}
</style>
......@@ -28,7 +28,10 @@
</div>
<div>
<el-button size="mini" @click="clickClose">{{ $t("Close") }}</el-button>
<el-button type="primary" size="mini" @click="clickSave">{{ $t("Save") }}</el-button>
<el-popconfirm v-if="skin" class="save-button" @onConfirm="clickSave" placement="top"
:title="$t('Click save will overwrite and apply immediately', {name: this.pxProjectName, skin: skin.name})">
<el-button slot="reference" type="primary" size="mini">{{ $t("Save") }}</el-button>
</el-popconfirm>
</div>
</div>
</el-dialog>
......@@ -46,6 +49,7 @@
data() {
return {
visible: false,
pxProjectName: '',
skin: null,
operate: 0,
rules: {
......@@ -59,7 +63,8 @@
}
},
methods: {
async edit(operate, skin) {
async edit(operate, skin, pxProjectName) {
this.pxProjectName = pxProjectName;
this.operate = operate;
this.skin = clonePureObj(skin);
if (!this.skin.html) {
......@@ -68,9 +73,9 @@
this.visible = true;
},
clickSave() {
if(!this.skin.html){
if (!this.skin.html) {
this.$message(this.$t('Skin html required'));
}else{
} else {
this.$refs.form.validate(async (valid) => {
if (valid) {
try {
......
......@@ -7,9 +7,12 @@
custom-class="flex-dialog px-skin-editor-dialog"
>
<div class="wrapper">
<div class="header">
<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>
<span class="px-project-name">{{pxProjectName}}</span>
</div>
<el-table class="mock-table" :data="skins" height="100%" stripe size="mini">
<el-table-column
prop="id"
......@@ -93,6 +96,7 @@
visible: false,
pxEnvs: this.$t("pxEnvs"),
tplTypes: this.$t("tplTypes"),
pxProjectName: '',
skins: [],
env: 'dev',
}
......@@ -114,11 +118,11 @@
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()});
this.$refs.pxSkinEditor.edit(0, {type: (type + 1).toString()}, this.pxProjectName);
}
},
editItem(skin) {
this.$refs.pxSkinEditor.edit(1, skin);
this.$refs.pxSkinEditor.edit(1, skin, this.pxProjectName);
},
copyUrl(skin) {
const {id, type} = skin;
......@@ -175,7 +179,8 @@
try {
const data = await getProjectSkins(pxPid, env);
if (data.success !== false) {
this.skins = data;
this.pxProjectName = data.name;
this.skins = data.skins;
} else {
// 如果是测试环境,ticket过期,则重新获取ticket
if (env === "test" && data.notLogin) {
......@@ -185,19 +190,23 @@
} else if (env === "prod" && data.notLogin) {
localStorage.setItem("prod_ticket", "");
this.$message({
message: this.$('Online ticket is invalid'),
message: this.$t('Online ticket is invalid'),
type: "info"
});
this.pxProjectName = '';
this.skins = [];
} else {
this.$message({
message: data.message,
type: "error"
});
this.pxProjectName = '';
this.skins = [];
}
}
} catch (e) {
this.pxProjectName = '';
this.skins = [];
throw new Error(e.message);
}
},
......
......@@ -25,7 +25,7 @@
</el-select>
<el-popover
placement="left-start"
:title="$t('All versions')"
:title="packageInfo.package_id + $t('All versions')"
:open-delay="500"
width="250"
style="margin-left: 5px;"
......@@ -39,7 +39,7 @@
{{packageInfo.update_times[index]}}
</span>
<br>
<span>{{packageInfo.remarks[index]}}</span>
<span v-if="packageInfo.remarks[index]" class="remark" v-html="translateRemark(packageInfo.remarks[index])"></span>
</div>
</el-scrollbar>
</div>
......@@ -118,6 +118,9 @@
let exists = packageExists(this.packageMetas, packageId, version);
return (withVersion ? version + ' ' : '') + (!exists ? '(待下载)' : '');
},
translateRemark(str){
return str.split('\n').map(item=>'·' + item).join('<br>')
},
...mapMutations([
'modifyDependencies',
]),
......
......@@ -5,17 +5,33 @@
</div>
<main>
<div class="project-list">
<el-form :inline="true" class="filter-bar" size="mini" @submit.native.prevent>
<el-form-item>
<el-input v-model="searchWord" :placeholder="$t('Search')" @change="search" @clear="search" clearable>
<el-button slot="append" icon="el-icon-search"/>
</el-input>
</el-form-item>
<el-form-item>
<el-checkbox
v-model="onlyMine"
size="mini">{{$t('Only mine')}}
</el-checkbox>
</el-form-item>
</el-form>
<div class="table">
<el-table
:data="projects.projects"
:empty-text="$t('No projects')"
height="100%"
stripe
>
<el-table-column label="ID" prop="id" width="140px"></el-table-column>
<el-table-column
:label="$t('Projects')">
<template slot-scope="scope">
<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="editor.operator === scope.row.operator ? 'success' : 'info'">{{scope.row.operator}}</el-tag>
<el-tag size="mini" type="warning">{{$timeFormat(scope.row.update_time)}}</el-tag>
</div>
</template>
......@@ -23,55 +39,25 @@
<el-table-column
fixed="right"
width="100">
<template slot="header" slot-scope="scope">
<el-checkbox
v-model="onlyMine"
size="mini">{{$t('Only mine')}}
</el-checkbox>
</template>
<template slot-scope="scope">
<!--<el-button
@click.native.prevent="selectProject(scope.row)"
type="primary" icon="el-icon-edit"
size="mini" plain>
{{$t('Edit')}}
</el-button>-->
<el-dropdown size="small" trigger="click" split-button @click="selectProject(scope.row)"
@command="(command)=>{onMoreMenu(command, scope.row)}">
<i class="el-icon-edit"></i>{{$t('Edit')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit" icon="el-icon-edit">{{$t('Edit')}}</el-dropdown-item>
<el-dropdown-item command="history" icon="el-icon-coin">{{$t('History')}}</el-dropdown-item>
<el-dropdown-item command="duplicate" icon="el-icon-document-copy">{{$t('Duplicate')}}</el-dropdown-item>
<el-dropdown-item command="duplicate" icon="el-icon-document-copy">{{$t('Duplicate')}}
</el-dropdown-item>
<el-dropdown-item command="export" icon="icon-download">{{$t('Export')}}</el-dropdown-item>
<el-dropdown-item command="delete" icon="el-icon-delete" v-if="showDeleteButton">{{$t('Delete')}}</el-dropdown-item>
<el-dropdown-item command="delete" icon="el-icon-delete" v-if="showDeleteButton">{{$t('Delete')}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!--<el-button
@click.native.prevent="selectFromHistory(scope.row)"
icon="el-icon-coin"
size="mini" plain
>{{$t('History')}}</el-button>
<el-button
@click.native.prevent="showDuplicateProjectDialog(scope.row)"
icon="el-icon-document-copy"
size="mini" plain
>{{$t('Duplicate')}}</el-button>
<el-button
@click.native.prevent="exportProject(scope.row)"
icon="icon-download"
size="mini" plain
>{{$t('Export')}}</el-button>
<el-button
v-if="showDeleteButton"
@click.native.prevent="onDeleteProject(scope.row)"
type="danger" icon="el-icon-delete"
size="mini" circle plain>
</el-button>-->
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="bottom-bar">
<div>
<el-button size="small" type="primary" @click="showCreateProjectDialog()">{{$t('Create')}}</el-button>
......@@ -99,21 +85,22 @@
import DuplicateProjectDialog from "./Home/DuplicateProjectDialog";
import {PROJECT_PAGE_SIZE} from "../config";
import ProjectHistoryDialog from "./Home/ProjectHistoryDialog";
import ElFormItem from "../components/inputs/form-item";
export default {
name: "Home",
components: {ProjectHistoryDialog, DuplicateProjectDialog, CreateProjectDialog},
components: {ElFormItem, ProjectHistoryDialog, DuplicateProjectDialog, CreateProjectDialog},
data() {
return {
appVersion: 'v1.0.0',
currentPage: 1,
pageSize: PROJECT_PAGE_SIZE,
searchWord: '',
onlyMine: true,
}
},
mounted() {
playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
});
playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {});
},
computed: {
showDeleteButton() {
......@@ -150,7 +137,7 @@
)
});
},
async onMoreMenu(command, project){
async onMoreMenu(command, project) {
switch (command) {
case 'edit':
this.selectProject(project);
......@@ -208,13 +195,17 @@
editProject(projectID) {
this.$router.push({name: 'editor', params: {projectID}});
},
async search() {
this.handleCurrentChange(1);
},
async handleCurrentChange(page) {
const loading = this.$loading({
lock: true,
text: this.$t('In processing'),
});
this.currentPage = page;
await this.fetchProjects({currentPage: page, pageSize: this.pageSize, onlyMine: this.onlyMine});
let keyword = this.searchWord;
await this.fetchProjects({keyword, currentPage: page, pageSize: this.pageSize, onlyMine: this.onlyMine});
loading.close();
},
...mapActions([
......
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