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