50 changed files with 1596 additions and 916 deletions
@ -0,0 +1,102 @@ |
|||||
|
{ |
||||
|
"name": "io.sc.platform.system.frontend", |
||||
|
"version": "8.1.38", |
||||
|
"description": "", |
||||
|
"private": false, |
||||
|
"keywords": [], |
||||
|
"author": "", |
||||
|
"license": "ISC", |
||||
|
"scripts": { |
||||
|
"dev": "nodemon", |
||||
|
"serve": "node ./util-components-generator.cjs && cross-env NODE_ENV=development webpack serve --config webpack.env.serve.cjs", |
||||
|
"build": "node ./util-components-generator.cjs && cross-env NODE_ENV=development webpack --config webpack.env.build.cjs", |
||||
|
"prod": "node ./util-components-generator.cjs && cross-env NODE_ENV=production webpack --config webpack.env.prod.cjs", |
||||
|
"sync": "platform sync", |
||||
|
"clean": "rm -rf ./node_modules && rm -rf pnpm-lock.yaml" |
||||
|
}, |
||||
|
"engines": { |
||||
|
"node": ">=18", |
||||
|
"pnpm": ">=7" |
||||
|
}, |
||||
|
"publishConfig": { |
||||
|
"registry": "http://nexus.sc.io:8000/repository/npm-releases/", |
||||
|
"access": "public" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@babel/core": "7.23.7", |
||||
|
"@babel/preset-env": "7.23.7", |
||||
|
"@babel/preset-typescript": "7.23.3", |
||||
|
"@babel/plugin-transform-class-properties": "7.23.3", |
||||
|
"@babel/plugin-transform-object-rest-spread": "7.23.4", |
||||
|
"@quasar/app-webpack": "3.12.1", |
||||
|
"@quasar/cli": "2.3.0", |
||||
|
"@types/mockjs": "1.0.10", |
||||
|
"@types/node": "20.10.6", |
||||
|
"@typescript-eslint/eslint-plugin": "6.17.0", |
||||
|
"@typescript-eslint/parser": "6.17.0", |
||||
|
"@vue/compiler-sfc": "3.4.3", |
||||
|
"@webpack-cli/serve": "2.0.5", |
||||
|
"autoprefixer": "10.4.16", |
||||
|
"babel-loader": "9.1.3", |
||||
|
"clean-webpack-plugin": "4.0.0", |
||||
|
"copy-webpack-plugin": "11.0.0", |
||||
|
"cross-env": "7.0.3", |
||||
|
"css-loader": "6.8.1", |
||||
|
"eslint": "8.56.0", |
||||
|
"eslint-config-prettier": "9.1.0", |
||||
|
"eslint-plugin-prettier": "5.1.2", |
||||
|
"eslint-plugin-vue": "9.19.2", |
||||
|
"eslint-webpack-plugin": "4.0.1", |
||||
|
"html-webpack-plugin": "5.6.0", |
||||
|
"json5": "2.2.3", |
||||
|
"mini-css-extract-plugin": "2.7.6", |
||||
|
"nodemon": "3.0.2", |
||||
|
"postcss": "8.4.32", |
||||
|
"postcss-import": "16.0.0", |
||||
|
"postcss-loader": "7.3.4", |
||||
|
"postcss-preset-env": "9.3.0", |
||||
|
"prettier": "3.1.1", |
||||
|
"sass": "1.69.7", |
||||
|
"sass-loader": "13.3.3", |
||||
|
"typescript": "5.3.3", |
||||
|
"vue-loader": "17.4.2", |
||||
|
"webpack": "5.89.0", |
||||
|
"webpack-bundle-analyzer": "4.10.1", |
||||
|
"webpack-cli": "5.1.4", |
||||
|
"webpack-dev-server": "4.15.1", |
||||
|
"webpack-merge": "5.10.0", |
||||
|
"@vue/babel-plugin-jsx": "1.1.5" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@codemirror/autocomplete": "6.11.1", |
||||
|
"@codemirror/commands": "6.3.3", |
||||
|
"@codemirror/lang-html": "6.4.7", |
||||
|
"@codemirror/lang-java": "6.0.1", |
||||
|
"@codemirror/lang-javascript": "6.2.1", |
||||
|
"@codemirror/lang-json": "6.0.1", |
||||
|
"@codemirror/lang-sql": "6.5.4", |
||||
|
"@codemirror/lang-xml": "6.0.2", |
||||
|
"@codemirror/language": "6.10.0", |
||||
|
"@codemirror/search": "6.5.5", |
||||
|
"@codemirror/state": "6.4.0", |
||||
|
"@codemirror/view": "6.23.0", |
||||
|
"@maxgraph/core": "0.9.0", |
||||
|
"@quasar/extras": "1.16.9", |
||||
|
"@vueuse/core": "10.7.1", |
||||
|
"axios": "1.6.3", |
||||
|
"codemirror": "6.0.1", |
||||
|
"dayjs": "1.11.10", |
||||
|
"echarts": "5.4.3", |
||||
|
"exceljs": "4.4.0", |
||||
|
"file-saver": "2.0.5", |
||||
|
"luckyexcel": "1.0.1", |
||||
|
"mockjs": "1.1.0", |
||||
|
"pinia": "2.1.7", |
||||
|
"quasar": "2.14.5", |
||||
|
"tailwindcss": "3.4.0", |
||||
|
"vue": "3.4.3", |
||||
|
"vue-dompurify-html": "5.0.1", |
||||
|
"vue-i18n": "9.8.0", |
||||
|
"vue-router": "4.2.5" |
||||
|
} |
||||
|
} |
@ -0,0 +1,157 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="row justify-end q-gutter-md q-py-md"> |
||||
|
<q-select |
||||
|
v-model="selectedTheme" |
||||
|
:label="$t('theme')" |
||||
|
:options="themeOptions" |
||||
|
option-label="name" |
||||
|
option-value="id" |
||||
|
emit-value |
||||
|
map-options |
||||
|
dense |
||||
|
outlined |
||||
|
style="min-width: 200px" |
||||
|
@update:model-value="themeChanged" |
||||
|
> |
||||
|
<template #option="scope"> |
||||
|
<q-item v-bind="scope.itemProps"> |
||||
|
<q-item-section> |
||||
|
<q-item-label>{{ scope.opt.name }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-if="scope.opt.active" avatar> |
||||
|
<q-icon name="bi-check" /> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-else avatar> |
||||
|
<w-icon-empty></w-icon-empty> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
</q-select> |
||||
|
<q-btn :label="$t('theme.action.setDefaultTheme')" icon="bi-heart" no-caps outline dense padding="2px 10px" @click="defaultTheme" /> |
||||
|
<q-btn :label="$t('add')" icon="add" no-caps outline dense padding="2px 10px" @click="prompt = true" /> |
||||
|
<q-btn :label="$t('delete')" icon="delete" no-caps outline dense padding="2px 10px" @click="removeTheme" /> |
||||
|
<q-btn :label="$t('save')" icon="save" no-caps outline dense padding="2px 10px" @click="saveTheme" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { useQuasar } from 'quasar'; |
||||
|
import { Environment, axios, Tools, NotifyManager } from 'platform-core'; |
||||
|
import Brand from './theme/Brand.vue'; |
||||
|
import LoadingBar from './theme/LoadingBar.vue'; |
||||
|
import Topper from './theme/Topper.vue'; |
||||
|
import Sider from './theme/Sider.vue'; |
||||
|
import TagViewBar from './theme/TagViewBar.vue'; |
||||
|
import Main from './theme/Main.vue'; |
||||
|
import Footer from './theme/Footer.vue'; |
||||
|
import Login from './theme/Login.vue'; |
||||
|
import Scroller from './theme/Scroller.vue'; |
||||
|
import Notifier from './theme/Notifier.vue'; |
||||
|
import Grid from './theme/Grid.vue'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
const quasar = useQuasar(); |
||||
|
|
||||
|
const selectedTab = ref('brand'); |
||||
|
const selectedTheme = ref(''); |
||||
|
const themeOptions = ref([]); |
||||
|
const prompt = ref(false); |
||||
|
const configureName = ref(''); |
||||
|
|
||||
|
let configureMap = new Map<string, object>(); |
||||
|
|
||||
|
const newTheme = () => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure'), { name: configureName.value }).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(() => { |
||||
|
selectedTheme.value = response.data.id; |
||||
|
configureName.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const themeChanged = (value) => { |
||||
|
const option = configureMap.get(value); |
||||
|
if (option) { |
||||
|
Tools.mergeObject(Environment.getConfigure(), option); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const defaultTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.setDefaultTheme.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure/activeConfigure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const removeTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.delete.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.delete(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
selectedTheme.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const saveTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.save.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
const data = {}; |
||||
|
Tools.mergeObject(data, configureMap.get(selectedTheme.value)); |
||||
|
data.theme = Environment.getConfigure().theme; |
||||
|
|
||||
|
axios.put(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value, data).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const refresh = (callback?: any) => { |
||||
|
axios.get(Environment.apiContextPath('/api/lcdp/configure')).then((response) => { |
||||
|
themeOptions.value.splice(0, themeOptions.value.length); |
||||
|
const items = response.data.content; |
||||
|
if (items && items.length > 0) { |
||||
|
const options = []; |
||||
|
for (const item of items) { |
||||
|
themeOptions.value.push(item); |
||||
|
configureMap.set(item.id, item); |
||||
|
if (item.active) { |
||||
|
selectedTheme.value = item.id; |
||||
|
} |
||||
|
} |
||||
|
//themeOptions.value = options; |
||||
|
if (callback) { |
||||
|
callback(); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
refresh(); |
||||
|
</script> |
@ -1,25 +1,160 @@ |
|||||
<template> |
<template> |
||||
<div class="w-full border rounded-md" style="height: 100%"> |
<div> |
||||
<ToolBar></ToolBar> |
<div class="row justify-end q-gutter-md q-py-md"> |
||||
<q-splitter :model-value="20" unit="%" separator-style="width:2px;" style="height: calc(100% - 50px)"> |
<q-select |
||||
<template #before> |
v-model="selectedTheme" |
||||
<SideBar></SideBar> |
:label="$t('theme')" |
||||
|
:options="themeOptions" |
||||
|
option-label="name" |
||||
|
option-value="id" |
||||
|
emit-value |
||||
|
map-options |
||||
|
dense |
||||
|
outlined |
||||
|
style="min-width: 200px" |
||||
|
@update:model-value="themeChanged" |
||||
|
> |
||||
|
<template #option="scope"> |
||||
|
<q-item v-bind="scope.itemProps"> |
||||
|
<q-item-section> |
||||
|
<q-item-label>{{ scope.opt.name }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-if="scope.opt.active" avatar> |
||||
|
<q-icon name="bi-check" /> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-else avatar> |
||||
|
<w-icon-empty></w-icon-empty> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
</template> |
</template> |
||||
<template #after> |
</q-select> |
||||
<q-splitter :model-value="65" unit="%" separator-style="width:2px;" style="height: 100%"> |
<q-btn :label="$t('theme.action.setDefaultTheme')" icon="bi-heart" no-caps outline dense padding="2px 10px" @click="defaultTheme" /> |
||||
<template #before><Editor></Editor></template> |
<q-btn :label="$t('add')" icon="add" no-caps outline dense padding="2px 10px" @click="prompt = true" /> |
||||
<template #after><Properties></Properties></template> |
<q-btn :label="$t('delete')" icon="delete" no-caps outline dense padding="2px 10px" @click="removeTheme" /> |
||||
</q-splitter> |
<q-btn :label="$t('save')" icon="save" no-caps outline dense padding="2px 10px" @click="saveTheme" /> |
||||
</template> |
|
||||
</q-splitter> |
|
||||
</div> |
</div> |
||||
</template> |
<q-dialog v-model="prompt" persistent> |
||||
|
<q-card style="min-width: 350px"> |
||||
|
<q-card-section class="q-pt-md"> |
||||
|
<q-input v-model="configureName" :label="$t('name')" outlined dense autofocus @keyup.enter="prompt = false" /> |
||||
|
</q-card-section> |
||||
|
|
||||
|
<q-card-actions align="right" class="text-primary"> |
||||
|
<q-btn v-close-popup flat :label="$t('cancel')" /> |
||||
|
<q-btn v-close-popup flat :label="$t('confirm')" @click="newTheme" /> |
||||
|
</q-card-actions> |
||||
|
</q-card> |
||||
|
</q-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import { ref, onMounted } from 'vue'; |
import { ref } from 'vue'; |
||||
import { type CellStyle, Graph, InternalEvent } from '@maxgraph/core'; |
import { useI18n } from 'vue-i18n'; |
||||
import ToolBar from './ToolBar.vue'; |
import { useQuasar } from 'quasar'; |
||||
import SideBar from './SideBar.vue'; |
import { Environment, axios, Tools, NotifyManager } from '@/platform'; |
||||
import Editor from './Editor.vue'; |
|
||||
import Properties from './Properties.vue'; |
const { t } = useI18n(); |
||||
|
const quasar = useQuasar(); |
||||
|
|
||||
|
const selectedTab = ref('brand'); |
||||
|
const selectedTheme = ref(''); |
||||
|
const themeOptions = ref([]); |
||||
|
const prompt = ref(false); |
||||
|
const configureName = ref(''); |
||||
|
|
||||
|
let configureMap = new Map<string, object>(); |
||||
|
|
||||
|
const newTheme = () => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure'), { name: configureName.value }).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(() => { |
||||
|
selectedTheme.value = response.data.id; |
||||
|
configureName.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const themeChanged = (value) => { |
||||
|
const option = configureMap.get(value); |
||||
|
if (option) { |
||||
|
Tools.mergeObject(Environment.getConfigure(), option); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const defaultTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.setDefaultTheme.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure/activeConfigure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const removeTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.delete.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.delete(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
selectedTheme.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const saveTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.save.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
const data = {}; |
||||
|
Tools.mergeObject(data, configureMap.get(selectedTheme.value)); |
||||
|
data.theme = Environment.getConfigure().theme; |
||||
|
|
||||
|
axios.put(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value, data).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const refresh = (callback?: any) => { |
||||
|
axios.get(Environment.apiContextPath('/api/lcdp/configure')).then((response) => { |
||||
|
configureMap.clear(); |
||||
|
const options = []; |
||||
|
selectedTheme.value = ''; |
||||
|
|
||||
|
const items = response.data.content; |
||||
|
if (items && items.length > 0) { |
||||
|
for (const item of items) { |
||||
|
options.push(item); |
||||
|
configureMap.set(item.id, item); |
||||
|
if (item.active) { |
||||
|
selectedTheme.value = item.id; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
themeOptions.value = options; |
||||
|
if (callback) { |
||||
|
callback(); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
refresh(); |
||||
</script> |
</script> |
||||
|
@ -0,0 +1,157 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="row justify-end q-gutter-md q-py-md"> |
||||
|
<q-select |
||||
|
v-model="selectedTheme" |
||||
|
:label="$t('theme')" |
||||
|
:options="themeOptions" |
||||
|
option-label="name" |
||||
|
option-value="id" |
||||
|
emit-value |
||||
|
map-options |
||||
|
dense |
||||
|
outlined |
||||
|
style="min-width: 200px" |
||||
|
@update:model-value="themeChanged" |
||||
|
> |
||||
|
<template #option="scope"> |
||||
|
<q-item v-bind="scope.itemProps"> |
||||
|
<q-item-section> |
||||
|
<q-item-label>{{ scope.opt.name }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-if="scope.opt.active" avatar> |
||||
|
<q-icon name="bi-check" /> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-else avatar> |
||||
|
<w-icon-empty></w-icon-empty> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
</q-select> |
||||
|
<q-btn :label="$t('theme.action.setDefaultTheme')" icon="bi-heart" no-caps outline dense padding="2px 10px" @click="defaultTheme" /> |
||||
|
<q-btn :label="$t('add')" icon="add" no-caps outline dense padding="2px 10px" @click="prompt = true" /> |
||||
|
<q-btn :label="$t('delete')" icon="delete" no-caps outline dense padding="2px 10px" @click="removeTheme" /> |
||||
|
<q-btn :label="$t('save')" icon="save" no-caps outline dense padding="2px 10px" @click="saveTheme" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { useQuasar } from 'quasar'; |
||||
|
import { Environment, axios, Tools, NotifyManager } from 'platform-core'; |
||||
|
import Brand from './theme/Brand.vue'; |
||||
|
import LoadingBar from './theme/LoadingBar.vue'; |
||||
|
import Topper from './theme/Topper.vue'; |
||||
|
import Sider from './theme/Sider.vue'; |
||||
|
import TagViewBar from './theme/TagViewBar.vue'; |
||||
|
import Main from './theme/Main.vue'; |
||||
|
import Footer from './theme/Footer.vue'; |
||||
|
import Login from './theme/Login.vue'; |
||||
|
import Scroller from './theme/Scroller.vue'; |
||||
|
import Notifier from './theme/Notifier.vue'; |
||||
|
import Grid from './theme/Grid.vue'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
const quasar = useQuasar(); |
||||
|
|
||||
|
const selectedTab = ref('brand'); |
||||
|
const selectedTheme = ref(''); |
||||
|
const themeOptions = ref([]); |
||||
|
const prompt = ref(false); |
||||
|
const configureName = ref(''); |
||||
|
|
||||
|
let configureMap = new Map<string, object>(); |
||||
|
|
||||
|
const newTheme = () => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure'), { name: configureName.value }).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(() => { |
||||
|
selectedTheme.value = response.data.id; |
||||
|
configureName.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const themeChanged = (value) => { |
||||
|
const option = configureMap.get(value); |
||||
|
if (option) { |
||||
|
Tools.mergeObject(Environment.getConfigure(), option); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const defaultTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.setDefaultTheme.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure/activeConfigure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const removeTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.delete.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.delete(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
selectedTheme.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const saveTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.save.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
const data = {}; |
||||
|
Tools.mergeObject(data, configureMap.get(selectedTheme.value)); |
||||
|
data.theme = Environment.getConfigure().theme; |
||||
|
|
||||
|
axios.put(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value, data).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const refresh = (callback?: any) => { |
||||
|
axios.get(Environment.apiContextPath('/api/lcdp/configure')).then((response) => { |
||||
|
themeOptions.value.splice(0, themeOptions.value.length); |
||||
|
const items = response.data.content; |
||||
|
if (items && items.length > 0) { |
||||
|
const options = []; |
||||
|
for (const item of items) { |
||||
|
themeOptions.value.push(item); |
||||
|
configureMap.set(item.id, item); |
||||
|
if (item.active) { |
||||
|
selectedTheme.value = item.id; |
||||
|
} |
||||
|
} |
||||
|
//themeOptions.value = options; |
||||
|
if (callback) { |
||||
|
callback(); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
refresh(); |
||||
|
</script> |
@ -1,25 +1,160 @@ |
|||||
<template> |
<template> |
||||
<div class="w-full border rounded-md" style="height: 100%"> |
<div> |
||||
<ToolBar></ToolBar> |
<div class="row justify-end q-gutter-md q-py-md"> |
||||
<q-splitter :model-value="20" unit="%" separator-style="width:2px;" style="height: calc(100% - 50px)"> |
<q-select |
||||
<template #before> |
v-model="selectedTheme" |
||||
<SideBar></SideBar> |
:label="$t('theme')" |
||||
|
:options="themeOptions" |
||||
|
option-label="name" |
||||
|
option-value="id" |
||||
|
emit-value |
||||
|
map-options |
||||
|
dense |
||||
|
outlined |
||||
|
style="min-width: 200px" |
||||
|
@update:model-value="themeChanged" |
||||
|
> |
||||
|
<template #option="scope"> |
||||
|
<q-item v-bind="scope.itemProps"> |
||||
|
<q-item-section> |
||||
|
<q-item-label>{{ scope.opt.name }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-if="scope.opt.active" avatar> |
||||
|
<q-icon name="bi-check" /> |
||||
|
</q-item-section> |
||||
|
<q-item-section v-else avatar> |
||||
|
<w-icon-empty></w-icon-empty> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
</template> |
</template> |
||||
<template #after> |
</q-select> |
||||
<q-splitter :model-value="65" unit="%" separator-style="width:2px;" style="height: 100%"> |
<q-btn :label="$t('theme.action.setDefaultTheme')" icon="bi-heart" no-caps outline dense padding="2px 10px" @click="defaultTheme" /> |
||||
<template #before><Editor></Editor></template> |
<q-btn :label="$t('add')" icon="add" no-caps outline dense padding="2px 10px" @click="prompt = true" /> |
||||
<template #after><Properties></Properties></template> |
<q-btn :label="$t('delete')" icon="delete" no-caps outline dense padding="2px 10px" @click="removeTheme" /> |
||||
</q-splitter> |
<q-btn :label="$t('save')" icon="save" no-caps outline dense padding="2px 10px" @click="saveTheme" /> |
||||
</template> |
|
||||
</q-splitter> |
|
||||
</div> |
</div> |
||||
</template> |
<q-dialog v-model="prompt" persistent> |
||||
|
<q-card style="min-width: 350px"> |
||||
|
<q-card-section class="q-pt-md"> |
||||
|
<q-input v-model="configureName" :label="$t('name')" outlined dense autofocus @keyup.enter="prompt = false" /> |
||||
|
</q-card-section> |
||||
|
|
||||
|
<q-card-actions align="right" class="text-primary"> |
||||
|
<q-btn v-close-popup flat :label="$t('cancel')" /> |
||||
|
<q-btn v-close-popup flat :label="$t('confirm')" @click="newTheme" /> |
||||
|
</q-card-actions> |
||||
|
</q-card> |
||||
|
</q-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import { ref, onMounted } from 'vue'; |
import { ref } from 'vue'; |
||||
import { type CellStyle, Graph, InternalEvent } from '@maxgraph/core'; |
import { useI18n } from 'vue-i18n'; |
||||
import ToolBar from './ToolBar.vue'; |
import { useQuasar } from 'quasar'; |
||||
import SideBar from './SideBar.vue'; |
import { Environment, axios, Tools, NotifyManager } from '@/platform'; |
||||
import Editor from './Editor.vue'; |
|
||||
import Properties from './Properties.vue'; |
const { t } = useI18n(); |
||||
|
const quasar = useQuasar(); |
||||
|
|
||||
|
const selectedTab = ref('brand'); |
||||
|
const selectedTheme = ref(''); |
||||
|
const themeOptions = ref([]); |
||||
|
const prompt = ref(false); |
||||
|
const configureName = ref(''); |
||||
|
|
||||
|
let configureMap = new Map<string, object>(); |
||||
|
|
||||
|
const newTheme = () => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure'), { name: configureName.value }).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(() => { |
||||
|
selectedTheme.value = response.data.id; |
||||
|
configureName.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const themeChanged = (value) => { |
||||
|
const option = configureMap.get(value); |
||||
|
if (option) { |
||||
|
Tools.mergeObject(Environment.getConfigure(), option); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const defaultTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.setDefaultTheme.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.post(Environment.apiContextPath('/api/lcdp/configure/activeConfigure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const removeTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.delete.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
axios.delete(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
refresh(); |
||||
|
selectedTheme.value = ''; |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const saveTheme = () => { |
||||
|
quasar |
||||
|
.dialog({ |
||||
|
title: t('confirm'), |
||||
|
message: t('theme.action.save.confirm', { themeName: configureMap.get(selectedTheme.value).name }), |
||||
|
cancel: true, |
||||
|
persistent: true, |
||||
|
}) |
||||
|
.onOk(() => { |
||||
|
const data = {}; |
||||
|
Tools.mergeObject(data, configureMap.get(selectedTheme.value)); |
||||
|
data.theme = Environment.getConfigure().theme; |
||||
|
|
||||
|
axios.put(Environment.apiContextPath('/api/lcdp/configure/') + selectedTheme.value, data).then((response) => { |
||||
|
NotifyManager.info(t('success')); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const refresh = (callback?: any) => { |
||||
|
axios.get(Environment.apiContextPath('/api/lcdp/configure')).then((response) => { |
||||
|
configureMap.clear(); |
||||
|
const options = []; |
||||
|
selectedTheme.value = ''; |
||||
|
|
||||
|
const items = response.data.content; |
||||
|
if (items && items.length > 0) { |
||||
|
for (const item of items) { |
||||
|
options.push(item); |
||||
|
configureMap.set(item.id, item); |
||||
|
if (item.active) { |
||||
|
selectedTheme.value = item.id; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
themeOptions.value = options; |
||||
|
if (callback) { |
||||
|
callback(); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
refresh(); |
||||
</script> |
</script> |
||||
|
@ -1,203 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<div class="row py-1 q-col-gutter-sm"> |
|
||||
<div class="col-2"> |
|
||||
<q-select |
|
||||
v-model="valueReactive.datasource" |
|
||||
:label="$t('developer.backend.export.liquibase.datasource')" |
|
||||
outlined |
|
||||
dense |
|
||||
emit-value |
|
||||
map-options |
|
||||
:options="datasourceOptionsRef" |
|
||||
@update:model-value=" |
|
||||
(value) => { |
|
||||
datasourceChanged(value); |
|
||||
} |
|
||||
" |
|
||||
></q-select> |
|
||||
</div> |
|
||||
<div class="col-2"> |
|
||||
<q-select |
|
||||
v-model="valueReactive.schema" |
|
||||
:label="$t('developer.backend.export.liquibase.schema')" |
|
||||
outlined |
|
||||
dense |
|
||||
emit-value |
|
||||
map-options |
|
||||
:options="schemaOptionsRef" |
|
||||
@update:model-value=" |
|
||||
(value) => { |
|
||||
schemaChanged(valueReactive.datasource, value); |
|
||||
} |
|
||||
" |
|
||||
></q-select> |
|
||||
</div> |
|
||||
<div class="col-8"> |
|
||||
<q-select |
|
||||
v-model="valueReactive.tables" |
|
||||
:label="$t('developer.backend.export.liquibase.tables')" |
|
||||
input-class="bg-red-200" |
|
||||
outlined |
|
||||
dense |
|
||||
emit-value |
|
||||
map-options |
|
||||
multiple |
|
||||
use-chips |
|
||||
:options="tablesOptionsRef" |
|
||||
@update:model-value=" |
|
||||
(value) => { |
|
||||
if (value) { |
|
||||
if (value.length > 1) { |
|
||||
valueReactive.sql = 'select * from ${table}'; |
|
||||
} else { |
|
||||
valueReactive.sql = 'select * from ' + value; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
" |
|
||||
> |
|
||||
<template #append> |
|
||||
<q-btn |
|
||||
:title="$t('selectAll')" |
|
||||
icon="bi-check-square" |
|
||||
flat |
|
||||
dense |
|
||||
:disable="!(tablesOptionsRef?.length > 0)" |
|
||||
@click.stop.prevent=" |
|
||||
() => { |
|
||||
const selecteds = []; |
|
||||
if (tablesOptionsRef) { |
|
||||
for (const table of tablesOptionsRef) { |
|
||||
selecteds.push(table.value); |
|
||||
} |
|
||||
} |
|
||||
valueReactive.tables = selecteds; |
|
||||
} |
|
||||
" |
|
||||
/> |
|
||||
<q-btn |
|
||||
:title="$t('unSelectAll')" |
|
||||
icon="bi-square" |
|
||||
flat |
|
||||
dense |
|
||||
:disable="!(tablesOptionsRef?.length > 0)" |
|
||||
@click.stop.prevent=" |
|
||||
() => { |
|
||||
valueReactive.tables = []; |
|
||||
} |
|
||||
" |
|
||||
/> |
|
||||
</template> |
|
||||
</q-select> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="row py-1 q-col-gutter-sm"> |
|
||||
<div class="col-12"> |
|
||||
<w-code-mirror v-model="valueReactive.sql" :label="$t('sql')" :rows="5" lang="sql"></w-code-mirror> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<div class="row justify-center q-gutter-md py-2"> |
|
||||
<WProgressBtn |
|
||||
ref="progressBtnRef" |
|
||||
icon="bi-database-down" |
|
||||
:label="$t('export')" |
|
||||
data-url="/api/jdbc/data/traceExporterExecuteProgress" |
|
||||
@click="exportData" |
|
||||
@success=" |
|
||||
(progressInfo) => { |
|
||||
Downloader.get(Environment.apiContextPath('/api/mvc/download?filePath=' + encodeURIComponent(progressInfo.result))); |
|
||||
} |
|
||||
" |
|
||||
></WProgressBtn> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, onMounted, onUpdated } from 'vue'; |
|
||||
import { useI18n } from 'vue-i18n'; |
|
||||
import { axios, blobAxios, Environment, DialogManager, Downloader } from '@/platform'; |
|
||||
import WProgressBtn from '../platform/components/progress/WProgressBtn.vue'; |
|
||||
|
|
||||
const { t } = useI18n(); |
|
||||
const progressBtnRef = ref(); |
|
||||
const datasourceOptionsRef = ref([]); |
|
||||
const schemaOptionsRef = ref([]); |
|
||||
const tablesOptionsRef = ref([]); |
|
||||
|
|
||||
const valueReactive = reactive({ |
|
||||
datasource: undefined, |
|
||||
schema: undefined, |
|
||||
tables: undefined, |
|
||||
sql: undefined, |
|
||||
}); |
|
||||
|
|
||||
const loadDatasource = () => { |
|
||||
axios.get(Environment.apiContextPath('/api/system/datasource?pageable=false&sortBy=name')).then((response) => { |
|
||||
const data = response?.data.content; |
|
||||
if (data && data.length > 0) { |
|
||||
datasourceOptionsRef.value.splice(0, datasourceOptionsRef.value.length); |
|
||||
for (let item of data) { |
|
||||
datasourceOptionsRef.value.push({ label: item.name, value: item.name }); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const datasourceChanged = (datasource: string) => { |
|
||||
datasource = datasource || ''; |
|
||||
axios.get(Environment.apiContextPath('/api/jdbc/metadata/getSchemas?datasource=' + datasource)).then((response) => { |
|
||||
const data = response?.data; |
|
||||
if (data && data.length > 0) { |
|
||||
schemaOptionsRef.value.splice(0, schemaOptionsRef.value.length); |
|
||||
tablesOptionsRef.value.splice(0, tablesOptionsRef.value.length); |
|
||||
for (let item of data) { |
|
||||
schemaOptionsRef.value.push({ label: item.name, value: item.name }); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const schemaChanged = (datasource: string, schema: string) => { |
|
||||
datasource = datasource || ''; |
|
||||
schema = schema || ''; |
|
||||
axios.get(Environment.apiContextPath('/api/jdbc/metadata/getTables?datasource=' + datasource + '&schema=' + schema)).then((response) => { |
|
||||
const data = response?.data; |
|
||||
if (data && data.length > 0) { |
|
||||
tablesOptionsRef.value.splice(0, tablesOptionsRef.value.length); |
|
||||
for (let item of data) { |
|
||||
tablesOptionsRef.value.push({ label: item.name, value: item.name }); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const exportData = (e) => { |
|
||||
DialogManager.confirm(t('developer.backend.export.liquibase.export.tip'), () => { |
|
||||
const data = valueReactive; |
|
||||
const config = { |
|
||||
datasource: data.datasource, |
|
||||
schema: data.schema, |
|
||||
tables: [], |
|
||||
}; |
|
||||
const length = data.tables.length; |
|
||||
const sql = length === 1 ? data.sql : ''; |
|
||||
for (let i = 0; i < length; i++) { |
|
||||
config.tables[i] = { name: data.tables[i], sql: sql ? sql : 'select * from ' + data.tables[i] }; |
|
||||
} |
|
||||
axios.post(Environment.apiContextPath('/api/jdbc/data/exportData'), config).then((response) => { |
|
||||
progressBtnRef.value.start(); |
|
||||
}); |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
loadDatasource(); |
|
||||
datasourceChanged(''); |
|
||||
}); |
|
||||
|
|
||||
onUpdated(() => { |
|
||||
loadDatasource(); |
|
||||
}); |
|
||||
</script> |
|
@ -0,0 +1,103 @@ |
|||||
|
{ |
||||
|
"name": "io.sc.platform.lcdp.frontend", |
||||
|
"version": "8.1.38", |
||||
|
"description": "", |
||||
|
"private": false, |
||||
|
"keywords": [], |
||||
|
"author": "", |
||||
|
"license": "ISC", |
||||
|
"scripts": { |
||||
|
"clean": "rm -rf ./node_modules && rm -rf pnpm-lock.yaml", |
||||
|
"dev": "nodemon", |
||||
|
"serve": "node ./util-components-generator.cjs && cross-env NODE_ENV=development webpack serve --config webpack.env.serve.cjs", |
||||
|
"build": "node ./util-components-generator.cjs && cross-env NODE_ENV=development webpack --config webpack.env.build.cjs", |
||||
|
"prod": "node ./util-components-generator.cjs && cross-env NODE_ENV=production webpack --config webpack.env.prod.cjs", |
||||
|
"sync": "platform sync" |
||||
|
}, |
||||
|
"engines": { |
||||
|
"node": ">=18", |
||||
|
"pnpm": ">=7" |
||||
|
}, |
||||
|
"publishConfig": { |
||||
|
"registry": "http://nexus.sc.io:8000/repository/npm-releases/", |
||||
|
"access": "public" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@babel/core": "7.23.7", |
||||
|
"@babel/preset-env": "7.23.7", |
||||
|
"@babel/preset-typescript": "7.23.3", |
||||
|
"@babel/plugin-transform-class-properties": "7.23.3", |
||||
|
"@babel/plugin-transform-object-rest-spread": "7.23.4", |
||||
|
"@quasar/app-webpack": "3.12.1", |
||||
|
"@quasar/cli": "2.3.0", |
||||
|
"@types/mockjs": "1.0.10", |
||||
|
"@types/node": "20.10.6", |
||||
|
"@typescript-eslint/eslint-plugin": "6.17.0", |
||||
|
"@typescript-eslint/parser": "6.17.0", |
||||
|
"@vue/compiler-sfc": "3.4.3", |
||||
|
"@webpack-cli/serve": "2.0.5", |
||||
|
"autoprefixer": "10.4.16", |
||||
|
"babel-loader": "9.1.3", |
||||
|
"clean-webpack-plugin": "4.0.0", |
||||
|
"copy-webpack-plugin": "11.0.0", |
||||
|
"cross-env": "7.0.3", |
||||
|
"css-loader": "6.8.1", |
||||
|
"eslint": "8.56.0", |
||||
|
"eslint-config-prettier": "9.1.0", |
||||
|
"eslint-plugin-prettier": "5.1.2", |
||||
|
"eslint-plugin-vue": "9.19.2", |
||||
|
"eslint-webpack-plugin": "4.0.1", |
||||
|
"html-webpack-plugin": "5.6.0", |
||||
|
"json5": "2.2.3", |
||||
|
"mini-css-extract-plugin": "2.7.6", |
||||
|
"nodemon": "3.0.2", |
||||
|
"postcss": "8.4.32", |
||||
|
"postcss-import": "16.0.0", |
||||
|
"postcss-loader": "7.3.4", |
||||
|
"postcss-preset-env": "9.3.0", |
||||
|
"prettier": "3.1.1", |
||||
|
"sass": "1.69.7", |
||||
|
"sass-loader": "13.3.3", |
||||
|
"typescript": "5.3.3", |
||||
|
"vue-loader": "17.4.2", |
||||
|
"webpack": "5.89.0", |
||||
|
"webpack-bundle-analyzer": "4.10.1", |
||||
|
"webpack-cli": "5.1.4", |
||||
|
"webpack-dev-server": "4.15.1", |
||||
|
"webpack-merge": "5.10.0", |
||||
|
"@vue/babel-plugin-jsx": "1.1.5" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@codemirror/autocomplete": "6.11.1", |
||||
|
"@codemirror/commands": "6.3.3", |
||||
|
"@codemirror/lang-html": "6.4.7", |
||||
|
"@codemirror/lang-java": "6.0.1", |
||||
|
"@codemirror/lang-javascript": "6.2.1", |
||||
|
"@codemirror/lang-json": "6.0.1", |
||||
|
"@codemirror/lang-sql": "6.5.4", |
||||
|
"@codemirror/lang-xml": "6.0.2", |
||||
|
"@codemirror/language": "6.10.0", |
||||
|
"@codemirror/search": "6.5.5", |
||||
|
"@codemirror/state": "6.4.0", |
||||
|
"@codemirror/view": "6.23.0", |
||||
|
"@maxgraph/core": "0.9.0", |
||||
|
"@quasar/extras": "1.16.9", |
||||
|
"@vueuse/core": "10.7.1", |
||||
|
"axios": "1.6.3", |
||||
|
"codemirror": "6.0.1", |
||||
|
"dayjs": "1.11.10", |
||||
|
"echarts": "5.4.3", |
||||
|
"exceljs": "4.4.0", |
||||
|
"file-saver": "2.0.5", |
||||
|
"luckyexcel": "1.0.1", |
||||
|
"mockjs": "1.1.0", |
||||
|
"pinia": "2.1.7", |
||||
|
"platform-core": "8.1.188", |
||||
|
"quasar": "2.14.5", |
||||
|
"tailwindcss": "3.4.0", |
||||
|
"vue": "3.4.3", |
||||
|
"vue-dompurify-html": "5.0.1", |
||||
|
"vue-i18n": "9.8.0", |
||||
|
"vue-router": "4.2.5" |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue