Commit 5b53ad72 authored by 张晨辰's avatar 张晨辰

feat: merge

parents e406eaeb 596fe898
No preview for this file type
{ {
"success": true, "success": true,
"data": { "data": {
"id": "6e1c9eadf8e28", "id": "6566c4a3f237",
"name": "测试", "name": "呼呼",
"creator": "卞龙亭", "creator": "卞龙亭",
"operator": "卞龙亭", "data": "{\"views\":[{\"name\":\"aaa\",\"type\":\"node\",\"children\":[{\"name\":\"node\",\"type\":\"image\"}]},{\"name\":\"aaa\",\"type\":\"node\",\"children\":[{\"name\":\"node\",\"type\":\"node\"},{\"name\":\"node\",\"type\":\"node\"}]}],\"assets\":[{\"name\":\"2ACA84D91EAAE90EDBFF78CBF5E727AB.png\",\"url\":\"//yun.duiba.com.cn/aurora/58323a0469a7467c99b34f8933ea65b507a0c655.png\",\"uuid\":\"3e496939-5fe6-42f2-b8fa-42c7a742e880\"},{\"name\":\"还以为是bug.jpg\",\"url\":\"//yun.duiba.com.cn/aurora/094832ace87c94bdb9e4a7821b3a3ebca0df2cd7.jpg\",\"uuid\":\"ec67a8a0-8708-43a4-888e-efb0fe7c2bd6\"},{\"name\":\"17344D055C89C3CFADB0C51E1A1E064E.gif\",\"url\":\"//yun.duiba.com.cn/aurora/1ad10a4cf3488ef1400af1d6f353d9c577fe1049.gif\",\"uuid\":\"429803eb-0f68-4071-b68c-468980883ac4\"}],\"dataMapping\":[]}"
"create_time": "2019-09-19T06:56:01.000Z",
"update_time": "2019-09-19T06:56:01.000Z",
"data": "{\"views\":[{\"name\":\"view1\",\"children\":[{\"name\":\"label\"},{\"name\":\"image\"}]},{\"name\":\"view2\"}],\"assets\":[{\"name\":\"bg.jpg\",\"url\":\"/bg.jpg\"},{\"name\":\"btn-join.png\",\"url\":\"/btn-join.png\"}]}"
} }
} }
\ No newline at end of file
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
}, },
"dependencies": { "dependencies": {
"cookie": "^0.4.0", "cookie": "^0.4.0",
"copy-to-clipboard": "^3.2.0",
"core-js": "^2.6.5", "core-js": "^2.6.5",
"duiba-draggable-resizable": "^1.0.9", "duiba-draggable-resizable": "^1.0.9",
"element-ui": "^2.4.5", "element-ui": "^2.4.5",
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
"path": "^0.12.7", "path": "^0.12.7",
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
"splitpanes": "^1.14.5", "splitpanes": "^1.14.5",
"string-width": "^4.1.0",
"uuid": "^3.3.3", "uuid": "^3.3.3",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-i18n": "^8.0.0", "vue-i18n": "^8.0.0",
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
this.timer = setInterval(() => { this.timer = setInterval(() => {
if (this.cd <= 0) { if (this.cd <= 0) {
clearInterval(this.timer); clearInterval(this.timer);
this.$router.push({name: 'home'}); this.$router.replace({name: 'home'});
return; return;
} }
this.cd--; this.cd--;
......
<template>
<p>{{ $t('hello') }}</p>
</template>
<script>
export default {
name: 'HelloI18n'
}
</script>
<i18n>
{
"en": {
"hello": "Hello i18n in SFC!"
}
}
</i18n>
<template> <template>
<div class="menu"> <div class="menu">
<el-link @click="clickItem(key)" v-for="(item, key) of data" :key="key" :icon="item.icon"> <el-badge class="menu-item" v-for="(item, key) of data" :key="key" is-dot :hidden="!menuBadge(key)">
{{item.text}} <el-link @click="clickItem(key)" :icon="item.icon">
</el-link> {{item.text}}
</el-link>
</el-badge>
</div> </div>
</template> </template>
<script> <script>
import {mapGetters} from 'vuex'
export default { export default {
name: "SampleMenu", name: "SampleMenu",
props: ['data'], props: ['data'],
data() { data() {
return {} return {}
}, },
computed: {
...mapGetters([
'menuBadge',
]),
},
methods: { methods: {
clickItem(key) { clickItem(key) {
this.$emit('click-menu', key); this.$emit('click-menu', key);
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
"Alert": "Alert", "Alert": "Alert",
"Confirm": "Confirm", "Confirm": "Confirm",
"Cancel": "Cancel", "Cancel": "Cancel",
"Close": "Close",
"Save": "Save", "Save": "Save",
"Copy": "Copy",
"Exit": "Exit",
"Add": "Add", "Add": "Add",
"Delete": "Delete", "Delete": "Delete",
"Import": "Import", "Import": "Import",
...@@ -15,6 +18,7 @@ ...@@ -15,6 +18,7 @@
"No projects": "No projects", "No projects": "No projects",
"Create": "Create", "Create": "Create",
"Project details": "Project details", "Project details": "Project details",
"Project does not exist": "Project does not exist",
"Project name": "Project name", "Project name": "Project name",
"Data mapping": "Data mapping", "Data mapping": "Data mapping",
"Template": "Template", "Template": "Template",
...@@ -22,6 +26,9 @@ ...@@ -22,6 +26,9 @@
"Deleting": "Deleting…", "Deleting": "Deleting…",
"Saving": "Saving…", "Saving": "Saving…",
"Create project": "Create project", "Create project": "Create project",
"Rename project": "Rename project",
"Input project name": "Input project name",
"Invalid project name": "Invalid project name",
"Creating project": "Creating project…", "Creating project": "Creating project…",
"Create project success": "Create project success", "Create project success": "Create project success",
"Duplicate project": "Duplicate project", "Duplicate project": "Duplicate project",
...@@ -44,9 +51,15 @@ ...@@ -44,9 +51,15 @@
"Remote Version": "Remote Version", "Remote Version": "Remote Version",
"Confirm to exit the editor": "Confirm to exit the editor?", "Confirm to exit the editor": "Confirm to exit the editor?",
"Confirm to publish": "Confirm to publish?", "Confirm to publish": "Confirm to publish?",
"Are you sure to delete this asset": "Are you sure to delete this asset",
"Are you sure to delete this link": "Are you sure to delete this link",
"Rename asset": "Rename asset",
"Input asset name": "Input asset name",
"Invalid asset name": "Invalid asset name",
"Copied field to clipboard": "Copied {field} to clipboard",
"Unsaved Alert": "You are leaving, but the project is not saved. Do you want to save it?",
"menu": { "menu": {
"save": "Save", "save": "Save",
"details": "Details",
"preview": "Preview", "preview": "Preview",
"publish": "Publish", "publish": "Publish",
"data-mapping": "DataMapping", "data-mapping": "DataMapping",
......
...@@ -23,9 +23,15 @@ export default new Vuex.Store({ ...@@ -23,9 +23,15 @@ export default new Vuex.Store({
plugins: [ plugins: [
SaveToLocalPlugin({ SaveToLocalPlugin({
mutationTypes: [ mutationTypes: [
'modifyProject',
'addNode', 'addNode',
'deleteNode', 'deleteNode',
'addAsset', 'addAsset',
'deleteAsset',
'modifyAsset',
'addDataMapping',
'deleteDataMapping',
'modifyDataMapping',
] ]
}) })
] ]
......
...@@ -5,6 +5,7 @@ import Vue from "vue"; ...@@ -5,6 +5,7 @@ import Vue from "vue";
import { projectApi } from "../../api"; import { projectApi } from "../../api";
import { compoleteComponentData } from '../../utils/compoleteCmpData'; import { compoleteComponentData } from '../../utils/compoleteCmpData';
import path from "path";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
export const projectStore = { export const projectStore = {
...@@ -18,14 +19,13 @@ export const projectStore = { ...@@ -18,14 +19,13 @@ export const projectStore = {
dataMapping: [], dataMapping: [],
}, },
activeComponent: {}, activeComponent: {},
activeIdList: [] activeIdList: [],
dirty: false,
}, },
mutations: { mutations: {
/** setDirty(state, dirty = true) {
* 更新state中的data state.dirty = dirty;
* @param {*} state },
* @param {*} project
*/
updateProject(state, project) { updateProject(state, project) {
const { id, name, creator, data } = project; const { id, name, creator, data } = project;
state.id = id; state.id = id;
...@@ -66,6 +66,9 @@ export const projectStore = { ...@@ -66,6 +66,9 @@ export const projectStore = {
state.activeComponent = id; state.activeComponent = id;
state.activeIdList = [id]; state.activeIdList = [id];
console.log('mutations activeComponent', state); console.log('mutations activeComponent', state);
},
modifyProject(state, ) {
}, },
addNode(state, { node, name, type }) { addNode(state, { node, name, type }) {
const child = { const child = {
...@@ -87,12 +90,46 @@ export const projectStore = { ...@@ -87,12 +90,46 @@ export const projectStore = {
}, },
addAsset(state, { url, file }) { addAsset(state, { url, file }) {
const ext = path.extname(file.name);
state.data.assets.push({ state.data.assets.push({
name: file.name, name: path.basename(file.name, ext),
ext,
url, url,
uuid: generateUUID(), uuid: generateUUID(),
}) })
}, },
deleteAsset(state, uuid) {
const { assets } = state.data;
for (let i = 0, li = assets.length; i < li; i++) {
const asset = state.data.assets[i];
if (asset.uuid === uuid) {
assets.splice(i, 1);
break;
}
}
},
modifyAsset(state, asset) {
},
addDataMapping(state, link) {
if (link) {
state.data.dataMapping.push(link);
} else {
state.data.dataMapping.push({
name: '',
path: '',
});
}
},
deleteDataMapping(state, index) {
state.data.dataMapping.splice(index, 1);
},
modifyDataMapping(state) {
},
}, },
getters: { getters: {
project(state) { project(state) {
...@@ -102,6 +139,15 @@ export const projectStore = { ...@@ -102,6 +139,15 @@ export const projectStore = {
data: JSON.stringify(data), data: JSON.stringify(data),
}; };
}, },
menuBadge: (state) => (key) => {
let result = false;
switch (key) {
case 'save':
result = state.dirty;
break;
}
return result;
},
/** /**
* 当前激活的组件 * 当前激活的组件
*/ */
...@@ -133,10 +179,11 @@ export const projectStore = { ...@@ -133,10 +179,11 @@ export const projectStore = {
} }
}, },
actions: { actions: {
saveToLocal({ getters }) { saveToLocal({ getters, commit }) {
const { project } = getters; const { project } = getters;
localStorage.setItem('project-' + project.id, JSON.stringify(project)); localStorage.setItem('project-' + project.id, JSON.stringify(project));
commit('setDirty', true);
}, },
localVersionExist({ commit }, projectID) { localVersionExist({ commit }, projectID) {
let json = localStorage.getItem('project-' + projectID); let json = localStorage.getItem('project-' + projectID);
...@@ -147,15 +194,21 @@ export const projectStore = { ...@@ -147,15 +194,21 @@ export const projectStore = {
if (json) { if (json) {
const project = JSON.parse(json); const project = JSON.parse(json);
commit('updateProject', project); commit('updateProject', project);
commit('setDirty', true);
} }
}, },
deleteLocalVersion({ state }, projectID) { deleteLocalVersion({ state, commit }, projectID) {
localStorage.removeItem('project-' + projectID); localStorage.removeItem('project-' + projectID);
commit('setDirty', false);
}, },
async loadFromRemote({ commit, dispatch }, projectID) { async loadFromRemote({ commit, dispatch }, projectID) {
const project = await projectApi.fetchOne(projectID); const project = await projectApi.fetchOne(projectID);
dispatch('deleteLocalVersion', projectID); if (project) {
commit('updateProject', project); dispatch('deleteLocalVersion', projectID);
commit('updateProject', project);
} else {
throw new Error('Project does not exist')
}
}, },
async saveToRemote({ state, dispatch, getters }) { async saveToRemote({ state, dispatch, getters }) {
await projectApi.saveOne(getters.project); await projectApi.saveOne(getters.project);
......
...@@ -26,15 +26,27 @@ ...@@ -26,15 +26,27 @@
flex-wrap: wrap; flex-wrap: wrap;
.file-item { .file-item {
width: 60px;
padding: 5px; padding: 5px;
color: $--color-text-regular; color: $--color-text-regular;
&:hover {
& > .icon > .operate-bar {
display: block;
}
& > .name > .full-name {
display: block;
}
}
.icon { .icon {
width: 60px; width: 100%;
height: 60px; height: 60px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative;
.thumbnail { .thumbnail {
max-width: 60px; max-width: 60px;
...@@ -44,14 +56,48 @@ ...@@ -44,14 +56,48 @@
.file-icon { .file-icon {
font-size: 60px; font-size: 60px;
} }
.operate-bar {
display: none;
position: absolute;
right: 1px;
bottom: 1px;
.el-button {
padding: 2px;
margin-left: 2px;
}
}
} }
.name { .name {
text-align: center; text-align: center;
font-size: 12px; font-size: 12px;
position: relative;
margin-top: 2px;
span {
word-break: break-all;
overflow:hidden;
text-overflow: ellipsis;
display:-webkit-box;
-webkit-line-clamp:2;
-webkit-box-orient:vertical;
}
width: 60px; .full-name {
overflow: hidden; display: none;
position: absolute;
top: 0;
left: 0;
background-color: $--color-text-secondary;
color: $--color-white;
border-radius: 5px;
padding: 2px;
z-index: 2;
width: 95%;
line-height: 17px;
}
} }
} }
...@@ -80,6 +126,10 @@ ...@@ -80,6 +126,10 @@
width: 100%; width: 100%;
flex: 1; flex: 1;
} }
.scrollbar-view{
padding-bottom: 5px;
}
} }
} }
...@@ -96,28 +146,25 @@ ...@@ -96,28 +146,25 @@
align-items: center; align-items: center;
padding: 30px; padding: 30px;
.close-button{ .close-button {
align-self: flex-end; align-self: flex-end;
} }
.name-bar { .name-bar {
margin-top: 5px;
color: $--color-white; color: $--color-white;
align-self: stretch; align-self: stretch;
.item + .item{
margin-top: 5px;
}
.item{ .item{
display: flex; .field{
.el-tag { width: 30px;
width: 40px; display: block;
text-align: right;
margin-right: 5px;
}
.value{
width: 0;
flex: 1;
overflow-wrap: break-word;
} }
} }
} }
.big-image { .big-image {
...@@ -130,6 +177,11 @@ ...@@ -130,6 +177,11 @@
} }
} }
.image-info{
color: $__color-white;
font-size: 12px;
}
.operate-bar { .operate-bar {
} }
......
...@@ -16,12 +16,21 @@ ...@@ -16,12 +16,21 @@
padding: 5px 10px; padding: 5px 10px;
font-size: 13px; font-size: 13px;
.menu{ .menu {
flex: 1; flex: 1;
a:not(:first-child){
.menu-item + .menu-item {
margin-left: 10px; margin-left: 10px;
} }
} }
.right-part{
color: $--color-text-regular;
.el-button{
padding: 2px;
}
}
} }
.pane-container { .pane-container {
...@@ -29,6 +38,53 @@ ...@@ -29,6 +38,53 @@
} }
} }
.bottom-bar, .toolbar{ .bottom-bar, .toolbar {
background-color: $--pane-background-color; background-color: $--pane-background-color;
} }
.data-mapping-dialog {
height: 200px;
display: flex;
flex-direction: column;
button{
align-self: flex-start;
}
.scrollbar{
flex: 1;
.view{
padding-right: 10px;
}
.item + .item{
margin-top: 10px;
}
.item{
display: flex;
align-items: center;
&:hover{
& > button{
visibility: visible;
}
}
.el-icon-connection{
padding: 0 5px;
}
button{
margin-left: 5px;
visibility: hidden;
}
}
}
}
.project-details-dialog {
}
\ No newline at end of file
/**
* Created by rockyl on 2019-09-19.
*/
import { Message, Loading } from "element-ui";
import i18n from './i18n'
export function messageError(e) {
Message({
dangerouslyUseHTMLString: true,
message: `<p style="margin-bottom: 5px;"><strong>${i18n.t(e.message)}</strong></p><p>${e.name}</p>`,
type: 'error'
})
}
export function playWaiting(promise, text) {
const loading = Loading.service({
lock: true,
text: text || i18n.t('In processing'),
});
return promise.catch(e => {
messageError(e);
throw e;
}).finally(() => {
loading.close();
})
}
\ No newline at end of file
...@@ -31,3 +31,17 @@ export function playWaiting(promise, text) { ...@@ -31,3 +31,17 @@ export function playWaiting(promise, text) {
export function guid() { export function guid() {
return `xy-${generateUUID()}`; return `xy-${generateUUID()}`;
} }
export function strEllipsis(str, maxLength = 0, rightOffset = 0) {
let result = str;
let strLen = str.length;//stringWidth(str);
if (strLen > maxLength) {
strLen += 1; //还有一个省略号占1个半角
let leftPart = str.substr(0, maxLength - rightOffset);
let rightPart = str.substr(strLen - rightOffset);
result = leftPart + '…' + rightPart;
}
return result;
}
...@@ -17,134 +17,143 @@ ...@@ -17,134 +17,143 @@
</template> </template>
<script> <script>
import { mapGetters, mapActions } from 'vuex'; import {mapGetters, mapActions} from 'vuex'
import SplitPanes from 'splitpanes'; import SplitPanes from 'splitpanes'
import ToolBar from './Editor/ToolBar'; import ToolBar from "./Editor/ToolBar";
import Inspector from './Editor/Inspector'; import Inspector from "./Editor/Inspector";
import Views from './Editor/Views'; import Views from "./Editor/Views";
import Playground from './Editor/Playground'; import Playground from "./Editor/Playground";
import Assets from './Editor/Assets'; import Assets from "./Editor/Assets";
import ProjectDetailsDialog from './Editor/dialogs/ProjectDetailsDialog'; import ProjectDetailsDialog from "./Editor/dialogs/ProjectDetailsDialog";
import DataMappingDialog from './Editor/dialogs/DataMappingDialog'; import DataMappingDialog from "./Editor/dialogs/DataMappingDialog";
import { playWaiting } from '../utils'; import {playWaiting} from "../utils";
import i18n from "../i18n";
export default { export default {
name: 'Editor', name: 'Editor',
components: { components: {
DataMappingDialog, DataMappingDialog,
ProjectDetailsDialog, ProjectDetailsDialog,
Assets, Assets,
Playground, Playground,
Views, Views,
Inspector, Inspector,
ToolBar, ToolBar,
SplitPanes SplitPanes,
}, },
data() { data() {
const panesConfig = localStorage.panesConfig ? JSON.parse(localStorage.panesConfig) : [0.8, 0.8, 0.3]; const panesConfig = localStorage.panesConfig ? JSON.parse(localStorage.panesConfig) : [0.8, 0.8, 0.3];
return { return {
panesConfig panesConfig,
}; }
}, },
computed: { computed: {
...mapGetters([]) ...mapGetters([]),
}, },
async mounted() { async mounted() {
const { projectID } = this.$route.params; const {projectID} = this.$route.params;
if (await this.localVersionExist(projectID)) { if (await this.localVersionExist(projectID)) {
this.$confirm(this.$t('Unsaved version found locally'), this.$t('Alert'), { this.$confirm(this.$t('Unsaved version found locally'), this.$t('Alert'), {
showClose: false, showClose: false,
closeOnClickModal: false, closeOnClickModal: false,
closeOnPressEscape: false, closeOnPressEscape: false,
confirmButtonText: this.$t('Local Version'), confirmButtonText: this.$t('Local Version'),
cancelButtonText: this.$t('Remote Version'), cancelButtonText: this.$t('Remote Version'),
type: 'warning' type: 'warning'
}) }).then(() => {
.then(() => { this.loadLocalVersion(projectID);
this.loadLocalVersion(projectID); }).catch((e) => {
}) if (e === 'cancel') {
.catch(e => { this.loadRemoteVersion(projectID);
if (e === 'cancel') { } else {
this.loadRemoteVersion(projectID); console.log(e);
} else { }
console.log(e); });
} } else {
}); this.loadRemoteVersion(projectID);
} else { }
this.loadRemoteVersion(projectID); },
} methods: {
}, loadLocalVersion(projectID) {
methods: { this.loadFromLocal(projectID)
loadLocalVersion(projectID) { },
this.loadFromLocal(projectID); loadRemoteVersion(projectID) {
}, if (projectID) {
loadRemoteVersion(projectID) { playWaiting(this.loadFromRemote(projectID), this.$t('Preparing')).catch(e => {
if (projectID) { this.$alert(this.$t('Project does not exist'), this.$t('Alert'), {
playWaiting(this.loadFromRemote(projectID), this.$t('Preparing')).catch(e => {}); confirmButtonText: this.$t('Confirm'),
} else { callback: action=>{
this.$router.push({ name: 'home' }); this.$router.replace({name: 'home'});
} }
}, });
getSize(id, side) { });
let ratio = this.panesConfig[id]; } else {
return (side === 0 ? ratio : 1 - ratio) * 100; this.$router.push({name: 'home'})
}, }
onPanesReSized(id, configs) { },
this.panesConfig[id] = configs[0].width / 100; getSize(id, side) {
localStorage.panesConfig = JSON.stringify(this.panesConfig); let ratio = this.panesConfig[id];
}, return (side === 0 ? ratio : 1 - ratio) * 100
async clickMenu(menuItem) { },
switch (menuItem) { onPanesReSized(id, configs) {
case 'save': this.panesConfig[id] = configs[0].width / 100;
try { localStorage.panesConfig = JSON.stringify(this.panesConfig);
await playWaiting(this.saveToRemote(), this.$t('Saving')); },
this.$message({ async saveProject() {
message: this.$t('Save project successfully'), await playWaiting(this.saveToRemote(), this.$t('Saving'));
type: 'success' this.$message({
}); message: i18n.t('Save project successfully'), //因为message是异步出现,但是当路由回退的时候,this.i18n的实例已经置空,所以要用全局的i18n实例
} catch (e) {} type: 'success'
break; });
case 'details': },
this.$refs.projectDialogsDialog.show(); async clickMenu(menuItem) {
break; switch (menuItem) {
case 'data-mapping': case 'save':
this.$refs.dataMappingDialog.show(); try {
break; this.saveProject();
case 'exit': } catch (e) {
this, exitConfirm(); }
break; break;
case 'publish': case 'details':
this.publishConfirm(); this.$refs.projectDialogsDialog.show();
break; break;
} case 'data-mapping':
}, this.$refs.dataMappingDialog.show();
/** break;
* 退出 case 'exit':
*/ const {projectID} = this.$route.params;
async exitConfirm() { if (await this.localVersionExist(projectID)) {
await this.$confirm(this.$t('Confirm to exit the editor'), { this.$confirm(this.$t('Unsaved Alert'), this.$t('Alert'), {
confirmButtonText: this.$t('Confirm'), confirmButtonText: this.$t('Save'),
cancelButtonText: this.$t('Cancle'), cancelButtonText: this.$t('Exit'),
type: 'warning' type: 'warning'
}); }).then(() => {
// todo try {
// exit this.saveProject();
}, this.backToHome();
/** } catch (e) {
* 发布 }
*/ }).catch((e) => {
async publishConfirm() { this.backToHome();
await this.$confirm(this.$t('Confirm to publish'), { });
confirmButtonText: this.$t('Confirm'), } else {
cancelButtonText: this.$t('Cancle'), this.backToHome();
type: 'warning' }
}); break;
// todo }
// publish },
}, backToHome() {
...mapActions(['localVersionExist', 'loadFromLocal', 'loadFromRemote', 'saveToLocal', 'saveToRemote']) this.$router.replace({name: 'home'});
} },
}; ...mapActions([
'localVersionExist',
'loadFromLocal',
'loadFromRemote',
"saveToLocal",
"saveToRemote",
])
}
}
</script> </script>
<style lang="scss"> <style lang="scss">
......
<template> <template>
<pane class="assets" icon="el-icon-s-shop" :title="$t('panes.Assets')"> <pane class="assets" icon="el-icon-s-shop" :title="$t('panes.Assets')">
<div class="container"> <div class="container">
<div class="header-bar"> <!--<div class="header-bar">
<el-link>{{$t('Upload')}}</el-link> <el-link>{{$t('Upload')}}</el-link>
</div> </div>-->
<el-scrollbar class="assets-scrollbar" wrap-class="wrap-x-hidden"> <el-scrollbar class="assets-scrollbar" wrap-class="wrap-x-hidden" view-class="scrollbar-view">
<div class="file-list"> <div class="file-list">
<el-upload <el-upload
class="file-uploader" class="file-uploader"
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
> >
<i class="el-icon-plus file-uploader-icon"></i> <i class="el-icon-plus file-uploader-icon"></i>
</el-upload> </el-upload>
<file-item v-for="file in assets" :data="file" :key="file.url" @show-file-details="showFileDetails"/> <file-item v-for="(file, index) in assets" :data="file" :key="index + '_' + file.url" @show-file-details="showFileDetails"/>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
}, },
uploadFileSuccess(response, file){ uploadFileSuccess(response, file){
if(response.success){ if(response.success){
console.log('upload success', response, file); //console.log('upload success', response, file);
this.addAsset({ this.addAsset({
url: response.url, url: response.url,
file, file,
......
...@@ -12,19 +12,21 @@ ...@@ -12,19 +12,21 @@
<div class="wrapper"> <div class="wrapper">
<el-button class="close-button" size="mini" circle icon="el-icon-close" @click="hide"></el-button> <el-button class="close-button" size="mini" circle icon="el-icon-close" @click="hide"></el-button>
<div class="name-bar"> <div class="name-bar">
<div class="item"> <el-input size="mini" class="item" v-model="file.name" readonly>
<el-tag size="mini" type="success">name</el-tag> <template slot="prepend"><span class="field">name</span></template>
<span class="value">{{file.name}}</span> <el-button slot="append" icon="el-icon-document-copy" @click="copyValue('name')"></el-button>
</div> </el-input>
<div class="item"> <el-input size="mini" class="item" v-model="file.url" readonly>
<el-tag size="mini" type="success">url</el-tag> <template slot="prepend"><span class="field">url</span></template>
<span class="value">{{file.url}}</span> <el-button slot="append" icon="el-icon-document-copy" @click="copyValue('url')"></el-button>
</div> </el-input>
</div>
<el-image class="big-image" :src="imageUrl" fit="contain" @load="onImageLoaded"/>
<div class="image-info">
<span class="size">{{size}}</span>
</div> </div>
<el-image class="big-image" :src="imageUrl" fit="contain"/>
<div class="operate-bar"> <div class="operate-bar">
<el-button-group> <el-button-group>
<el-button size="mini" icon="el-button-loading">复制</el-button>
</el-button-group> </el-button-group>
</div> </div>
</div> </div>
...@@ -34,6 +36,7 @@ ...@@ -34,6 +36,7 @@
</template> </template>
<script> <script>
import copy from 'copy-to-clipboard'
export default { export default {
name: "AssetsShow", name: "AssetsShow",
...@@ -41,10 +44,16 @@ ...@@ -41,10 +44,16 @@
return { return {
visible: false, visible: false,
file: null, file: null,
size: '',
}
},
watch: {
file(){
this.size = '';
} }
}, },
computed: { computed: {
imageUrl(){ imageUrl() {
return this.file.url; return this.file.url;
}, },
}, },
...@@ -66,9 +75,21 @@ ...@@ -66,9 +75,21 @@
afterLeave() { afterLeave() {
this.$emit('closed'); this.$emit('closed');
}, },
handleWrapperClick(){ handleWrapperClick() {
this.hide(); this.hide();
}, },
copyValue(field) {
copy(this.file[field]);
this.$message({
message: this.$t('Copied field to clipboard', {field}),
type: 'success',
duration: 700,
});
},
onImageLoaded(e) {
const {width, height} = e.target;
this.size = width + ' x ' + height;
}
} }
} }
</script> </script>
......
<template> <template>
<div class="file-item" @dblclick="onDbclick()"> <div class="file-item">
<div class="icon"> <div class="icon">
<i v-if="!showThumbnail" class="file-icon" :class="fileIcon"></i> <i v-if="!showThumbnail" class="file-icon" :class="fileIcon"></i>
<img v-if="showThumbnail" class="thumbnail" :src="thumbnailUrl" alt="thumb"> <img v-if="showThumbnail" class="thumbnail" :src="thumbnailUrl" alt="thumb" @dblclick="onDbclick()">
<div class="operate-bar">
<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"/>
</div>
</div> </div>
<div class="name"> <div class="name">
<span>{{data.name}}</span> <span>{{data.name}}</span>
<span class="full-name">{{data.name}}</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {mapMutations} from "vuex";
import {fileTypeIcon} from "../../../config"; import {fileTypeIcon} from "../../../config";
import path from "path"; import {strEllipsis} from "../../../utils";
export default { export default {
name: "FileItem", name: "FileItem",
props: ['data'], props: ['data'],
data() { data() {
return { return {
ext: '',
} }
}, },
watch: { watch: {
data() {
this.updateExt();
}
},
mounted() {
this.updateExt();
}, },
computed: { computed: {
fileIcon() { fileIcon() {
return 'icon-' + fileTypeIcon[this.ext]; return 'icon-' + fileTypeIcon[this.data.ext];
}, },
showThumbnail() { showThumbnail() {
return fileTypeIcon[this.ext] === 't'; return fileTypeIcon[this.data.ext] === 't';
}, },
thumbnailUrl(){ thumbnailUrl() {
return this.data.url; return this.data.url;
}, },
ellipsisName(){
return strEllipsis(this.data.name, 14, 5);
},
}, },
methods: { methods: {
updateExt() { onDbclick() {
this.ext = path.extname(this.data.name);
},
onDbclick(){
this.$emit('show-file-details', this.data); this.$emit('show-file-details', this.data);
} },
onClickDelete() {
this.$confirm(this.$t('Are you sure to delete this asset'), this.$t('Alert'), {
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning'
}).then(() => {
this.deleteAsset(this.data.uuid);
}).catch((e) => {
});
},
onClickEdit() {
this.$prompt(this.$t('Input asset name'), this.$t('Rename asset'), {
inputValue: this.data.name,
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
closeOnClickModal: false,
inputPattern: /^.{1,256}$/,
inputErrorMessage: this.$t('Invalid asset name'),
}).then(({value}) => {
this.$set(this.data, 'name', value);
this.modifyAsset();
}).catch(() => {
});
},
...mapMutations([
'deleteAsset',
'modifyAsset',
]),
} }
} }
</script> </script>
......
<template> <template>
<div class="tool-bar"> <div class="tool-bar">
<sample-menu :data="menu" @click-menu="clickMenu"/> <sample-menu :data="menu" @click-menu="clickMenu"/>
<div> <div class="right-part">
[{{project.name}}] <span>
[{{project.name}}]
<el-button size="mini" circle icon="el-icon-edit" @click="editProjectName"/>
</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {mapState, mapActions} from 'vuex' import {mapState, mapActions, mapMutations} from 'vuex'
import SampleMenu from "../../components/SampleMenu"; import SampleMenu from "../../components/SampleMenu";
export default { export default {
...@@ -32,7 +35,24 @@ ...@@ -32,7 +35,24 @@
methods: { methods: {
clickMenu(menuItem) { clickMenu(menuItem) {
this.$emit('click-menu', menuItem); this.$emit('click-menu', menuItem);
} },
editProjectName(){
this.$prompt(this.$t('Input project name'), this.$t('Rename project'), {
inputValue: this.project.name,
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
closeOnClickModal: false,
inputPattern: /^.{1,64}$/,
inputErrorMessage: this.$t('Invalid project name'),
}).then(({value}) => {
this.$set(this.project, 'name', value);
this.modifyProject();
}).catch(() => {
});
},
...mapMutations([
'modifyProject'
]),
} }
} }
</script> </script>
......
<template> <template>
<el-dialog :title="$t('Data mapping')" width="70%" :visible.sync="visible" @open="onOpen" <el-dialog :title="$t('Data mapping')" width="70%" :visible.sync="visible" @open="onOpen"
:append-to-body="true"> :append-to-body="true" :close-on-click-modal="false">
<div class="data-mapping-dialog">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<div class="item" v-for="(link, index) in mapping">
<el-input size="mini" style="width: 30%" v-model="link.name" @change="onChange"/>
<el-icon class="el-icon-connection"/>
<el-input size="mini" v-model="link.path" @change="onChange"/>
<el-button icon="el-icon-minus" circle size="mini" @click="toDeleteItem(link, index)"/>
</div>
</el-scrollbar>
</div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button> <el-button size="mini" type="primary" @click="onAdd">{{$t('Add')}}</el-button>
<el-button size="mini" type="primary" @click="onConfirm">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" @click="onConfirm">{{$t('Confirm')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import {mapState, mapMutations} from 'vuex'
export default { export default {
name: "DataMappingDialog", name: "DataMappingDialog",
data() { data() {
...@@ -17,16 +28,42 @@ ...@@ -17,16 +28,42 @@
visible: false, visible: false,
} }
}, },
computed: {
...mapState({
mapping: state=> state.project.data.dataMapping,
}),
},
methods: { methods: {
show(){ show() {
this.visible = true; this.visible = true;
}, },
onConfirm(){ onAdd() {
this.addDataMapping();
},
onChange(){
this.modifyDataMapping();
},
toDeleteItem(link, index){
this.$confirm(this.$t('Are you sure to delete this link'), this.$t('Alert'), {
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning'
}).then(() => {
this.deleteDataMapping(index);
}).catch((e) => {
});
},
onConfirm() {
this.visible = false;
}, },
onOpen(){ onOpen() {
}, },
...mapMutations([
'addDataMapping',
'deleteDataMapping',
'modifyDataMapping',
]),
} }
} }
</script> </script>
......
<template> <template>
<el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @open="onOpen" <el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @open="onOpen"
:close-on-click-modal="false"
:append-to-body="true"> :append-to-body="true">
<div class="project-details-dialog">
<el-form v-model="project">
<el-form-item prop="">
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button> <el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button>
<el-button size="mini" type="primary" @click="onConfirm">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" @click="onConfirm">{{$t('Save')}}</el-button>
...@@ -10,6 +17,8 @@ ...@@ -10,6 +17,8 @@
</template> </template>
<script> <script>
import {mapState} from 'vuex';
export default { export default {
name: "ProjectDetailsDialog", name: "ProjectDetailsDialog",
data() { data() {
...@@ -17,6 +26,11 @@ ...@@ -17,6 +26,11 @@
visible: false, visible: false,
} }
}, },
computed: {
...mapState([
'project',
]),
},
methods: { methods: {
show(){ show(){
this.visible = true; this.visible = true;
......
...@@ -2248,6 +2248,13 @@ copy-descriptor@^0.1.0: ...@@ -2248,6 +2248,13 @@ copy-descriptor@^0.1.0:
resolved "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" resolved "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
copy-to-clipboard@^3.2.0:
version "3.2.0"
resolved "https://registry.npm.taobao.org/copy-to-clipboard/download/copy-to-clipboard-3.2.0.tgz#d2724a3ccbfed89706fac8a894872c979ac74467"
integrity sha1-0nJKPMv+2JcG+siolIcsl5rHRGc=
dependencies:
toggle-selection "^1.0.6"
copy-webpack-plugin@^4.6.0: copy-webpack-plugin@^4.6.0:
version "4.6.0" version "4.6.0"
resolved "https://registry.npm.taobao.org/copy-webpack-plugin/download/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" resolved "https://registry.npm.taobao.org/copy-webpack-plugin/download/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae"
...@@ -2911,6 +2918,11 @@ emoji-regex@^7.0.1: ...@@ -2911,6 +2918,11 @@ emoji-regex@^7.0.1:
resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY= integrity sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=
emojis-list@^2.0.0: emojis-list@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
...@@ -4225,6 +4237,11 @@ is-fullwidth-code-point@^2.0.0: ...@@ -4225,6 +4237,11 @@ is-fullwidth-code-point@^2.0.0:
resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=
is-glob@^3.1.0: is-glob@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" resolved "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
...@@ -7212,6 +7229,15 @@ string-width@^3.0.0, string-width@^3.1.0: ...@@ -7212,6 +7229,15 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0" is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0" strip-ansi "^5.1.0"
string-width@^4.1.0:
version "4.1.0"
resolved "https://registry.npm.taobao.org/string-width/download/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff"
integrity sha1-uoRtHaqXw8WWFVMIBj4HXtHJmv8=
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^5.2.0"
string.prototype.padend@^3.0.0: string.prototype.padend@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npm.taobao.org/string.prototype.padend/download/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" resolved "https://registry.npm.taobao.org/string.prototype.padend/download/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
...@@ -7492,6 +7518,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: ...@@ -7492,6 +7518,11 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2" regex-not "^1.0.2"
safe-regex "^1.1.0" safe-regex "^1.1.0"
toggle-selection@^1.0.6:
version "1.0.6"
resolved "https://registry.npm.taobao.org/toggle-selection/download/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
toidentifier@1.0.0: toidentifier@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" resolved "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
...@@ -7764,12 +7795,7 @@ utils-merge@1.0.1: ...@@ -7764,12 +7795,7 @@ utils-merge@1.0.1:
resolved "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" resolved "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
uuid@^3.0.1, uuid@^3.3.2: uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3:
version "3.3.3"
resolved "https://registry.npm.taobao.org/uuid/download/uuid-3.3.3.tgz?cache=0&sync_timestamp=1566221202613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha1-RWjwIW54dg7h2/Ok0s9T4iQRKGY=
uuid@^3.3.3:
version "3.3.3" version "3.3.3"
resolved "https://registry.npm.taobao.org/uuid/download/uuid-3.3.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" resolved "https://registry.npm.taobao.org/uuid/download/uuid-3.3.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha1-RWjwIW54dg7h2/Ok0s9T4iQRKGY= integrity sha1-RWjwIW54dg7h2/Ok0s9T4iQRKGY=
......
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