Compare commits
10 Commits
4f920b0ac2
...
99015ecbd2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
99015ecbd2 | ||
![]() |
db10bb6a6c | ||
![]() |
8d0c890061 | ||
![]() |
9d25cddcb3 | ||
![]() |
0852dd98f0 | ||
![]() |
9b2c728d4c | ||
![]() |
eecc2b1893 | ||
![]() |
261dd5bb67 | ||
![]() |
47c9ec1aba | ||
![]() |
dd69823a00 |
@ -8,4 +8,10 @@ VITE_BASE_URL = /
|
||||
VITE_PORT = 10011
|
||||
# VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
VITE_DEBUG_MODE = true
|
||||
VITE_DEBUG_MODE = true
|
||||
|
||||
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://localhost:10010/'
|
||||
Y_CODE_DESIGNER_URL = 'https://localhost:10011/'
|
||||
Y_CODE_RENDERER_URL = 'https://localhost:10012/'
|
@ -5,3 +5,8 @@ VITE_NODE_ENV = 'production'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform.shiyuegame.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer.shiyuegame.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer.shiyuegame.com/'
|
||||
|
@ -5,4 +5,8 @@ VITE_NODE_ENV = 'staging'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# base api url
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform-pre.shiyue.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer-pre.shiyue.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer-pre.shiyue.com/'
|
||||
|
@ -13,22 +13,23 @@
|
||||
"clean": "rimraf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vtj/core": "^0.10.9",
|
||||
"@vtj/designer": "0.10.9",
|
||||
"@vtj/icons": "0.10.9",
|
||||
"@vtj/local": "^0.10.9",
|
||||
"@vtj/materials": "^0.10.9",
|
||||
"@vtj/core": "^0.10.10",
|
||||
"@vtj/designer": "0.10.10",
|
||||
"@vtj/icons": "0.10.10",
|
||||
"@vtj/local": "^0.10.10",
|
||||
"@vtj/materials": "^0.10.10",
|
||||
"@vtj/node": "0.10.2",
|
||||
"@vtj/pro": "^0.10.9",
|
||||
"@vtj/renderer": "^0.10.9",
|
||||
"@vtj/ui": "^0.10.9",
|
||||
"@vtj/utils": "0.10.9",
|
||||
"@vtj/web": "^0.10.9",
|
||||
"@vtj/pro": "^0.10.10",
|
||||
"@vtj/renderer": "^0.10.10",
|
||||
"@vtj/ui": "^0.10.10",
|
||||
"@vtj/utils": "0.10.10",
|
||||
"@vtj/web": "^0.10.10",
|
||||
"axios": "^1.8.1",
|
||||
"element-plus": "^2.9.4",
|
||||
"licia-es": "^1.46.0",
|
||||
"pinia": "^3.0.1",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
"postmate": "^1.5.2",
|
||||
"unplugin-auto-import": "^19.1.1",
|
||||
"vue": "~3.5.13",
|
||||
"vue-router": "~4.5.0"
|
||||
|
@ -1,38 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps<{ msg: string }>()
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<button type="button" @click="count++">count is {{ count }}</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test HMR
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out
|
||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
||||
>create-vue</a
|
||||
>, the official Vue + Vite starter
|
||||
</p>
|
||||
<p>
|
||||
Install
|
||||
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
|
||||
in your IDE for a better DX
|
||||
</p>
|
||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
2
apps/designer/src/constants/env.ts
Normal file
2
apps/designer/src/constants/env.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// @ts-ignore
|
||||
export const currentEnv = __APP_ENV__;
|
1
apps/designer/src/constants/index.ts
Normal file
1
apps/designer/src/constants/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './env';
|
@ -1,7 +1,6 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const apiBase = import.meta.env.VITE_BASE_API_URL;
|
||||
console.log('apiBase', apiBase);
|
||||
|
||||
// 创建独立实例
|
||||
const instance = axios.create({
|
||||
|
@ -8,7 +8,7 @@ export const pinia = createPinia();
|
||||
// 用户模块 store
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// 状态定义
|
||||
const token = ref<string>(localStorage.getItem('token') || '');
|
||||
const token = ref<string>(localStorage.getItem('y-code-access-token') || '');
|
||||
const userProfile = ref<null>(null);
|
||||
|
||||
// getter 计算属性
|
||||
@ -17,20 +17,14 @@ export const useUserStore = defineStore('user', () => {
|
||||
// 同步 action
|
||||
const setToken = (newToken: string) => {
|
||||
token.value = newToken;
|
||||
localStorage.setItem('token', newToken);
|
||||
};
|
||||
|
||||
// 异步 action
|
||||
const fetchProfile = async () => {
|
||||
const { data } = await axios.get('/api/user/profile');
|
||||
userProfile.value = data;
|
||||
localStorage.setItem('y-code-access-token', newToken);
|
||||
};
|
||||
|
||||
// 清理方法
|
||||
const logout = () => {
|
||||
token.value = '';
|
||||
userProfile.value = null;
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('y-code-access-token');
|
||||
};
|
||||
|
||||
return {
|
||||
@ -38,7 +32,6 @@ export const useUserStore = defineStore('user', () => {
|
||||
userProfile,
|
||||
isLoggedIn,
|
||||
setToken,
|
||||
fetchProfile,
|
||||
logout
|
||||
};
|
||||
});
|
||||
|
@ -1,40 +1,71 @@
|
||||
<template>
|
||||
<div class="designer-container" ref="container"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
Engine,
|
||||
widgetManager
|
||||
// type ProjectModel
|
||||
} from '@vtj/pro';
|
||||
|
||||
import Postmate from 'postmate';
|
||||
import { Engine, widgetManager } from '@vtj/pro';
|
||||
import { request, jsonp } from '@vtj/utils';
|
||||
import { useUserStore } from '@/store';
|
||||
import { LowCodeService } from '@/service';
|
||||
|
||||
const container = ref();
|
||||
const service = new LowCodeService();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const engine = new Engine({
|
||||
container,
|
||||
service,
|
||||
project: {
|
||||
// @ts-ignore
|
||||
id: 4,
|
||||
name: '低代码平台'
|
||||
}
|
||||
});
|
||||
onMounted(async () => {
|
||||
// 数据模型
|
||||
const model = {
|
||||
name: '',
|
||||
url: '',
|
||||
applicationId: -1,
|
||||
projectId: -1,
|
||||
accessToken: ''
|
||||
};
|
||||
|
||||
widgetManager.set('Previewer', {
|
||||
props: {
|
||||
path: (block: any) => {
|
||||
const pathname = location.pathname;
|
||||
return `${pathname}#/preview/${block.id}`;
|
||||
}
|
||||
}
|
||||
const handshake = new Postmate.Model({});
|
||||
await handshake.then((parent) => {
|
||||
parent.emit('sync-context', 'y-code-designer is ready');
|
||||
Object.assign(model, parent.model);
|
||||
// console.log('get parent model', model);
|
||||
userStore.setToken(model.accessToken);
|
||||
request.useRequest((req) => {
|
||||
req.headers.set('Authorization', `Bearer ${model.accessToken}`);
|
||||
return req;
|
||||
});
|
||||
const engine = new Engine({
|
||||
container,
|
||||
service,
|
||||
project: {
|
||||
// @ts-ignore
|
||||
id: model.projectId,
|
||||
name: model.name
|
||||
},
|
||||
adapter: {
|
||||
request,
|
||||
jsonp
|
||||
}
|
||||
});
|
||||
widgetManager.set('Previewer', {
|
||||
props: {
|
||||
path: (block: any) => {
|
||||
const pathname = location.pathname;
|
||||
return `${pathname}#/preview/${block.id}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
widgetManager.set('Templates', {
|
||||
invisible: true
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="designer-container"
|
||||
ref="container"
|
||||
:token="userStore.token"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.designer-container {
|
||||
height: 100%;
|
||||
|
@ -1,12 +1,20 @@
|
||||
<template>
|
||||
<component v-if="renderer" :is="renderer"></component>
|
||||
<component v-if="renderer" :is="renderer" v-bind="$attrs"></component>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, getCurrentInstance } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { createProvider, ContextMode } from '@vtj/pro';
|
||||
import { LowCodeService } from '@/service';
|
||||
import { request, jsonp } from '@vtj/utils';
|
||||
import { useUserStore } from '@/store';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const service = new LowCodeService();
|
||||
request.useRequest((req) => {
|
||||
req.headers.set('Authorization', `Bearer ${userStore.token}`);
|
||||
return req;
|
||||
});
|
||||
const { provider, onReady } = createProvider({
|
||||
mode: ContextMode.Runtime,
|
||||
service,
|
||||
@ -14,6 +22,10 @@ const { provider, onReady } = createProvider({
|
||||
// @ts-ignore
|
||||
id: 4
|
||||
},
|
||||
adapter: {
|
||||
request,
|
||||
jsonp
|
||||
},
|
||||
dependencies: {
|
||||
Vue: () => import('vue'),
|
||||
VueRouter: () => import('vue-router'),
|
||||
|
@ -35,7 +35,7 @@ const config = createViteConfig({
|
||||
export default defineConfig(({ mode }) => {
|
||||
console.log('mode', mode);
|
||||
// 加载环境变量(支持 .env.development/.env.production)
|
||||
const env = loadEnv(mode, process.cwd(), ['VITE_', 'VTJ_', 'SY_']);
|
||||
const env = loadEnv(mode, process.cwd(), ['VITE_', 'VTJ_', 'SY_', 'Y_CODE_']);
|
||||
return {
|
||||
...config,
|
||||
server: {
|
||||
|
@ -6,6 +6,13 @@ VITE_BASE_URL = /
|
||||
|
||||
# 前端可见变量(必须以 VITE_ 开头)
|
||||
VITE_PORT = 10010
|
||||
# VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
VITE_DEBUG_MODE = true
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
# VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
|
||||
VITE_DEBUG_MODE = true
|
||||
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://localhost:10010/'
|
||||
Y_CODE_DESIGNER_URL = 'https://localhost:10011/'
|
||||
Y_CODE_RENDERER_URL = 'https://localhost:10012/'
|
||||
Y_CODE_V1_URL = 'https://localhost:10013/'
|
@ -5,3 +5,8 @@ VITE_NODE_ENV = 'production'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform.shiyuegame.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer.shiyuegame.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer.shiyuegame.com/'
|
||||
Y_CODE_V1_URL = 'https://custom-chart.shiyuegame.com/'
|
@ -5,4 +5,9 @@ VITE_NODE_ENV = 'staging'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# base api url
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform-pre.shiyue.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer-pre.shiyue.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer-pre.shiyue.com/'
|
||||
Y_CODE_V1_URL = 'https://custom-chart.shiyue.com/'
|
@ -1,42 +1,3 @@
|
||||
## 安装使用
|
||||
# 因为项目接入了天梯登陆,使用前需要申请天梯的悦码权限
|
||||
|
||||
- 安装依赖
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
|
||||
```
|
||||
|
||||
- 运行
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
- 打包
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## vscode 配置
|
||||
|
||||
安装项目根目录 `.vscode` 推荐的插件,再安装 `Volar`,并禁用 `Vetur`,重启 vscode 即可。
|
||||
|
||||
## Git 贡献提交规范
|
||||
|
||||
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
|
||||
|
||||
- `feat` 增加新功能
|
||||
- `fix` 修复问题/BUG
|
||||
- `style` 代码风格相关无影响运行结果的
|
||||
- `perf` 优化/性能提升
|
||||
- `refactor` 重构
|
||||
- `revert` 撤销修改
|
||||
- `test` 测试相关
|
||||
- `docs` 文档/注释
|
||||
- `chore` 依赖更新/脚手架配置修改等
|
||||
- `workflow` 工作流改进
|
||||
- `ci` 持续集成
|
||||
- `types` 类型定义文件更改
|
||||
- `wip` 开发中
|
||||
天梯地址 https://auth-pro.shiyue.com/
|
||||
|
@ -29,9 +29,11 @@
|
||||
"@ant-design/icons-vue": "~7.0.1",
|
||||
"@iconify/vue": "^4.3.0",
|
||||
"@iframe-resizer/parent": "^5.3.3",
|
||||
"@sy/unified-login": "1.0.29",
|
||||
"@sy/y-code-renderer-adapter": "workspace:*",
|
||||
"@tanstack/query-core": "^5.66.4",
|
||||
"@tanstack/vue-query": "^5.66.9",
|
||||
"@vue/runtime-core": "^3.5.13",
|
||||
"@vueuse/core": "~11.1.0",
|
||||
"ant-design-vue": "~4.2.6",
|
||||
"axios": "~1.8.1",
|
||||
@ -51,9 +53,9 @@
|
||||
"vue": "~3.5.13",
|
||||
"vue-i18n": "^11.1.1",
|
||||
"vue-router": "~4.4.5",
|
||||
"vue-types": "~5.1.3",
|
||||
"vue-types": "~6.0.0",
|
||||
"vue-virtual-scroller": "2.0.0-beta.8",
|
||||
"wujie": "^1.0.25",
|
||||
"wujie-vue3": "^1.0.25",
|
||||
"xlsx": "~0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -62,9 +64,9 @@
|
||||
"@iconify-json/ant-design": "^1.2.5",
|
||||
"@iconify-json/ep": "^1.2.2",
|
||||
"@iconify/json": "^2.2.307",
|
||||
"@sy/y-code-designer": "workspace:*",
|
||||
"@sy/low-code-shared": "workspace:*",
|
||||
"@sy/vite-plugin-http2-proxy": "workspace:*",
|
||||
"@sy/y-code-designer": "workspace:*",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/lodash-es": "~4.17.12",
|
||||
"@types/node": "~22.7.9",
|
||||
@ -74,8 +76,8 @@
|
||||
"@typescript-eslint/parser": "~8.11.0",
|
||||
"@umijs/openapi": "^1.13.0",
|
||||
"@vitejs/plugin-vue": "~5.1.5",
|
||||
"@vitejs/plugin-vue-jsx": "~4.0.1",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"@vitejs/plugin-vue-jsx": "~4.1.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"commitizen": "~4.3.1",
|
||||
"conventional-changelog-cli": "~4.1.0",
|
||||
"cross-env": "~7.0.3",
|
||||
@ -90,9 +92,9 @@
|
||||
"lint-staged": "~15.2.11",
|
||||
"msw": "^2.7.0",
|
||||
"postcss": "~8.4.49",
|
||||
"postcss-html": "~1.7.0",
|
||||
"postcss-html": "~1.8.0",
|
||||
"postcss-less": "~6.0.0",
|
||||
"prettier": "~3.3.3",
|
||||
"prettier": "~3.5.3",
|
||||
"rimraf": "~6.0.1",
|
||||
"stylelint": "~16.10.0",
|
||||
"stylelint-config-property-sort-order-smacss": "^10.0.0",
|
||||
@ -101,7 +103,7 @@
|
||||
"stylelint-config-standard": "~36.0.1",
|
||||
"stylelint-order": "~6.0.4",
|
||||
"stylelint-prettier": "^5.0.3",
|
||||
"typescript": "~5.6.3",
|
||||
"typescript": "~5.8.2",
|
||||
"unocss": "^65.5.0",
|
||||
"unplugin-vue-components": "~0.27.5",
|
||||
"vite": "~6.2.0",
|
||||
@ -110,8 +112,8 @@
|
||||
"vite-plugin-mkcert": "^1.17.6",
|
||||
"vite-plugin-svg-icons": "~2.0.1",
|
||||
"vite-plugin-vue-inspector": "^5.3.1",
|
||||
"vue-eslint-parser": "~9.4.3",
|
||||
"vue-tsc": "~2.1.10"
|
||||
"vue-eslint-parser": "~10.1.1",
|
||||
"vue-tsc": "~2.2.8"
|
||||
},
|
||||
"keywords": [
|
||||
"vue",
|
||||
|
@ -19,12 +19,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
import { theme } from 'ant-design-vue';
|
||||
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
import { LockScreen } from '@/components/basic/lockscreen';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const userStore = useUserStore();
|
||||
userStore.login();
|
||||
|
||||
const { compactAlgorithm } = theme;
|
||||
</script>
|
||||
|
@ -1,21 +1,24 @@
|
||||
<template>
|
||||
<!-- <div id="container" /> -->
|
||||
<iframe
|
||||
<!-- <iframe
|
||||
ref="iframeRef"
|
||||
width="100%"
|
||||
style="border: none"
|
||||
height="100%"
|
||||
:src="route.meta?.app?.url"
|
||||
/>
|
||||
<!-- <component :is="WujieVue" v-bind="route.meta?.app" /> -->
|
||||
/> -->
|
||||
<WujieVue width="100%" height="100%" v-bind="route.meta?.app" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { setupApp, startApp } from 'wujie';
|
||||
// import { setupApp, startApp } from 'wujie';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import WujieVue from 'wujie-vue3';
|
||||
|
||||
const route = useRoute();
|
||||
console.log(route.meta?.app);
|
||||
// console.log(route.meta?.app);
|
||||
// onMounted(() => {
|
||||
// setupApp({
|
||||
// el: '#container',
|
||||
|
@ -2,32 +2,37 @@
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import Postmate from 'postmate';
|
||||
import { Spin, Alert, Button } from 'ant-design-vue';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
// import { Spin, Alert, Button } from 'ant-design-vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
console.log('userStore', userStore);
|
||||
|
||||
const route = useRoute();
|
||||
const MAX_RETRIES = 3;
|
||||
// const MAX_RETRIES = 3;
|
||||
|
||||
const loading = ref(true);
|
||||
const errorMessage = ref('');
|
||||
const retryCount = ref(0);
|
||||
// const retryCount = ref(0);
|
||||
|
||||
const initPostmate = async () => {
|
||||
loading.value = true;
|
||||
errorMessage.value = '';
|
||||
const container = document.getElementById('low-code-adapter');
|
||||
console.log('container', container);
|
||||
if (!container) {
|
||||
errorMessage.value = '容器元素未找到';
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const handle = new Postmate({
|
||||
const connection = new Postmate({
|
||||
container,
|
||||
url: route.meta?.app?.url,
|
||||
name: 'y-code-renderer',
|
||||
classListArray: ['responsive-iframe'],
|
||||
model: {
|
||||
accessToken: userStore.token,
|
||||
name: route.meta?.app?.name,
|
||||
applicationId: route.meta?.app?.applicationId,
|
||||
projectId: route.meta?.app?.projectId,
|
||||
@ -36,23 +41,27 @@
|
||||
},
|
||||
});
|
||||
|
||||
handle
|
||||
.then((instance) => {
|
||||
console.log('Postmate连接成功', instance);
|
||||
retryCount.value = 0; // 重置重试计数器
|
||||
})
|
||||
.catch((err) => {
|
||||
retryCount.value++;
|
||||
errorMessage.value = `连接失败: ${err.message}`;
|
||||
if (retryCount.value < MAX_RETRIES) {
|
||||
initPostmate(); // 自动重试
|
||||
} else {
|
||||
errorMessage.value = '已达到最大重试次数,请检查网络连接';
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
connection.then((child) => {
|
||||
console.log('Postmate 连接成功', child);
|
||||
child.on('some-event', (data) => console.log(data)); // Logs "Hello, World!"
|
||||
child.call('sayHi', {
|
||||
name: route.meta?.app?.name,
|
||||
});
|
||||
|
||||
// retryCount.value = 0; // 重置重试计数器
|
||||
});
|
||||
// .catch((err) => {
|
||||
// retryCount.value++;
|
||||
// errorMessage.value = `连接失败: ${err.message}`;
|
||||
// if (retryCount.value < MAX_RETRIES) {
|
||||
// initPostmate(); // 自动重试
|
||||
// } else {
|
||||
// errorMessage.value = '已达到最大重试次数,请检查网络连接';
|
||||
// }
|
||||
// })
|
||||
// .finally(() => {
|
||||
// loading.value = false;
|
||||
// });
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
@ -61,18 +70,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="iframe-container">
|
||||
<div id="low-code-adapter" />
|
||||
|
||||
<!-- <div v-if="loading" class="loading-overlay">
|
||||
<Spin :tip="`正在连接应用(${retryCount + 1}/${MAX_RETRIES})`" />
|
||||
</div> -->
|
||||
|
||||
<!-- <div v-if="errorMessage" class="error-overlay">
|
||||
<Alert type="error" :message="errorMessage" show-icon />
|
||||
<Button v-if="retryCount < MAX_RETRIES" @click="initPostmate">重新连接</Button>
|
||||
</div> -->
|
||||
</div>
|
||||
<div id="low-code-adapter" />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@ -85,39 +83,8 @@
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iframe-container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#low-code-adapter {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.error-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1001;
|
||||
height: 99%;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,6 +2,16 @@ export const devMode = 'development';
|
||||
|
||||
export const prodMode = 'production';
|
||||
|
||||
export const isDevMode = import.meta.env.DEV;
|
||||
export const stagingMode = 'staging';
|
||||
|
||||
export const isProdMode = import.meta.env.PROD;
|
||||
// @ts-ignore
|
||||
export const currentEnv = __APP_ENV__;
|
||||
|
||||
export const isDevMode = import.meta.env.MODE === devMode;
|
||||
export const isProdMode = import.meta.env.MODE === prodMode;
|
||||
export const isStagingMode = import.meta.env.MODE === stagingMode;
|
||||
|
||||
export const Y_CODE_RENDERER_URL = currentEnv.Y_CODE_RENDERER_URL;
|
||||
export const Y_CODE_DESIGNER_URL = currentEnv.Y_CODE_DESIGNER_URL;
|
||||
export const Y_CODE_PLATFORM_URL = currentEnv.Y_CODE_PLATFORM_URL;
|
||||
export const Y_CODE_V1_URL = currentEnv.Y_CODE_V1_URL;
|
||||
|
@ -1 +1,3 @@
|
||||
export * from '@sy/low-code-shared/constants';
|
||||
// export * from '@sy/low-code-shared/constants';
|
||||
export * from './env';
|
||||
export * from './low-code';
|
||||
|
2
apps/platform/src/constants/low-code.ts
Normal file
2
apps/platform/src/constants/low-code.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const LOW_CODE_APPLICATION_ID = 0;
|
||||
export const LOW_CODE_PROJECT_ID = 4;
|
16
apps/platform/src/io/file.ts
Normal file
16
apps/platform/src/io/file.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import instance from './instance';
|
||||
|
||||
export const uploadFile = async (data: FormData) => {
|
||||
const response = await instance.post('/api/v1/files/upload', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteFile = async (id: string) => {
|
||||
const response = await instance.delete(`/api/v1/files/upload/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getFileList = async () => {
|
||||
const response = await instance.get('/api/v1/files/upload');
|
||||
return response.data;
|
||||
};
|
@ -1,41 +1,41 @@
|
||||
import axios from 'axios';
|
||||
// import { useUserStore } from '@/store/modules/user';
|
||||
// import router from '@/router';
|
||||
import appClient from '@/io/tianti';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import router from '@/router';
|
||||
|
||||
// axios拦截器
|
||||
const { reqInterceptor, resInterceptor } = appClient.getInterceptor();
|
||||
|
||||
const baseApiUrl = import.meta.env.VITE_BASE_API_URL;
|
||||
|
||||
// 创建独立实例
|
||||
const instance = axios.create({
|
||||
baseURL: baseApiUrl, // 基础URL直接放在实例配置中
|
||||
baseURL: baseApiUrl,
|
||||
});
|
||||
|
||||
// 请求拦截器改为使用实例
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
// 可在此处添加统一请求头等配置
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
(config) => config,
|
||||
(error) => Promise.reject(error),
|
||||
);
|
||||
instance.interceptors.request.use(reqInterceptor.fulfilled, reqInterceptor.rejected);
|
||||
|
||||
// 响应拦截器改为使用实例
|
||||
// 响应拦截器
|
||||
instance.interceptors.response.use(
|
||||
(response) => {
|
||||
// 如果响应数据中 code 为 -1,清空登录状态并跳转到登录页
|
||||
if (response?.data?.code === -1) {
|
||||
// 检查是否为401未授权错误
|
||||
if (response.data.code === 401) {
|
||||
const userStore = useUserStore();
|
||||
userStore.clearLoginStatus(); // 清空用户信息
|
||||
router.push('/login'); // 直接使用路由实例
|
||||
console.error('请求失败:', response.data.msg);
|
||||
console.log('用户未授权或登录已过期,即将跳转...');
|
||||
// userStore.logout();
|
||||
// 返回一个永远不会resolve的Promise,防止后续代码执行
|
||||
return new Promise(() => {});
|
||||
}
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
(error) => Promise.reject(error),
|
||||
);
|
||||
instance.interceptors.response.use(resInterceptor.fulfilled, resInterceptor.rejected);
|
||||
|
||||
// 导出实例
|
||||
export default instance;
|
||||
|
12
apps/platform/src/io/tianti.ts
Normal file
12
apps/platform/src/io/tianti.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @ts-ignore
|
||||
import AxiosAppClient from '@sy/unified-login/es/app-client/axios';
|
||||
|
||||
export type Env = 'dev' | 'test' | 'pre' | 'prod';
|
||||
|
||||
const appClient = new AxiosAppClient({
|
||||
appKey: 'y-code', // 应用标识,不同项目不能一样
|
||||
env: 'prod', // dev:本地开发;test:测试;pre:预发布;prod:正式
|
||||
devBaseUrl: `https://localhost:${import.meta.env.VITE_PORT}`, // 应用开发环境地址
|
||||
});
|
||||
|
||||
export default appClient;
|
@ -9,3 +9,102 @@ export const logout = async () => {
|
||||
const response = await instance.post('/logout');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户信息接口
|
||||
*/
|
||||
export interface UserInfo {
|
||||
/** 用户ID */
|
||||
UserID: number;
|
||||
/** 用户名 */
|
||||
Username: string;
|
||||
/** 头像URL */
|
||||
Avatar: string;
|
||||
/** 用户别名/真实姓名 */
|
||||
Alias: string;
|
||||
/** 创建时间 */
|
||||
CreatedAt: string;
|
||||
/** 更新时间 */
|
||||
UpdatedAt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @returns {Promise<{code: number, data: UserInfo, message: string}>} 返回包含用户信息的响应对象
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const userInfo = await getCurrentUser();
|
||||
* console.log(userInfo.data.Username); // 输出当前用户名
|
||||
* ```
|
||||
*/
|
||||
export const getCurrentUser = async () => {
|
||||
const response = await instance.get('/api/v1/users/current');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取指定用户信息
|
||||
*
|
||||
* @param {number|string} id 用户ID
|
||||
* @returns {Promise<{code: number, data: UserInfo, message: string}>} 返回包含用户信息的响应对象
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 获取ID为2594的用户信息
|
||||
* const userInfo = await getUserById(2594);
|
||||
* console.log(userInfo.data.Username); // 输出用户名
|
||||
* ```
|
||||
*/
|
||||
export const getUserById = async (id: number | string) => {
|
||||
const response = await instance.get(`/api/v1/users/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户列表项接口
|
||||
*/
|
||||
export interface UserListItem {
|
||||
/** 用户ID */
|
||||
user_id: number;
|
||||
/** 用户名 */
|
||||
username: string;
|
||||
/** 头像URL */
|
||||
avatar: string;
|
||||
/** 用户别名/真实姓名 */
|
||||
alias: string;
|
||||
/** 创建时间 */
|
||||
created_at: string;
|
||||
/** 更新时间 */
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户列表查询参数
|
||||
*/
|
||||
export interface UserListParams {
|
||||
/** 页码,默认1 */
|
||||
page?: number | string;
|
||||
/** 每页数量,默认20 */
|
||||
per_page?: number | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*
|
||||
* @param {UserListParams} params 查询参数,包含页码和每页数量
|
||||
* @returns {Promise<{code: number, data: {list: UserListItem[], total: number}, message: string}>} 返回包含用户列表的响应对象
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 获取第1页,每页20条记录
|
||||
* const result = await getUserList({ page: 1, per_page: 20 });
|
||||
* console.log(`总用户数: ${result.data.total}`);
|
||||
* console.log(`第一个用户: ${result.data.list[0].username}`);
|
||||
* ```
|
||||
*/
|
||||
export const getUserList = async (params: UserListParams = {}) => {
|
||||
const response = await instance.get('/api/v1/users', { params });
|
||||
return response.data;
|
||||
};
|
||||
|
@ -33,10 +33,15 @@
|
||||
</Menu.Item> -->
|
||||
<Menu.Divider />
|
||||
<Menu.Item>
|
||||
<div @click.prevent="doLogout">
|
||||
<div @click.prevent="tianti.logout">
|
||||
<poweroff-outlined /> {{ $t('layout.header.dropdownItemLoginOut') }}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
<Menu.Item v-if="isDevEnv">
|
||||
<div @click.prevent="tianti.openDev">
|
||||
{{ $t('layout.header.openDev') }}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</template>
|
||||
</Dropdown>
|
||||
@ -49,6 +54,8 @@
|
||||
<script lang="tsx" setup>
|
||||
import { computed, type CSSProperties } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import tianti from '@/io/tianti';
|
||||
|
||||
import {
|
||||
QuestionCircleOutlined,
|
||||
MenuFoldOutlined,
|
||||
@ -71,6 +78,8 @@
|
||||
import { LOGIN_NAME } from '@/router/constant';
|
||||
import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
|
||||
|
||||
const isDevEnv = import.meta.env.VITE_NODE_ENV === 'development';
|
||||
|
||||
defineProps({
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
|
@ -1,20 +1,20 @@
|
||||
{
|
||||
"footer": { "onlinePreview": "在线预览", "onlineDocument": "在线文档" },
|
||||
"footer": {
|
||||
"onlinePreview": "在线预览",
|
||||
"onlineDocument": "在线文档"
|
||||
},
|
||||
"header": {
|
||||
"dropdownItemDoc": "文档",
|
||||
"dropdownItemLoginOut": "退出系统",
|
||||
|
||||
"openDev": "打开开发环境",
|
||||
"tooltipErrorLog": "错误日志",
|
||||
"tooltipLock": "锁定屏幕",
|
||||
"tooltipNotify": "消息通知",
|
||||
|
||||
"tooltipEntryFull": "全屏",
|
||||
"tooltipExitFull": "退出全屏",
|
||||
|
||||
"lockScreenPassword": "锁屏密码",
|
||||
"lockScreen": "锁定屏幕",
|
||||
"lockScreenBtn": "锁定",
|
||||
|
||||
"home": "首页"
|
||||
},
|
||||
"multipleTab": {
|
||||
@ -38,20 +38,15 @@
|
||||
"menuTypeMixSidebar": "左侧菜单混合模式",
|
||||
"menuTypeMix": "顶部菜单混合模式",
|
||||
"menuTypeTopMenu": "顶部菜单模式",
|
||||
|
||||
"on": "开",
|
||||
"off": "关",
|
||||
"minute": "分钟",
|
||||
|
||||
"operatingTitle": "操作成功",
|
||||
"operatingContent": "复制成功,请到 src/settings/projectSetting.ts 中修改配置!",
|
||||
"resetSuccess": "重置成功!",
|
||||
|
||||
"copyBtn": "拷贝",
|
||||
"clearBtn": "清空缓存并返回登录页",
|
||||
|
||||
"drawerTitle": "项目配置",
|
||||
|
||||
"darkMode": "主题",
|
||||
"navMode": "导航栏模式",
|
||||
"interfaceFunction": "界面功能",
|
||||
@ -59,11 +54,9 @@
|
||||
"animation": "动画",
|
||||
"splitMenu": "分割菜单",
|
||||
"closeMixSidebarOnChange": "切换页面关闭菜单",
|
||||
|
||||
"sysTheme": "系统主题",
|
||||
"headerTheme": "顶栏主题",
|
||||
"sidebarTheme": "菜单主题",
|
||||
|
||||
"menuDrag": "侧边菜单拖拽",
|
||||
"menuSearch": "菜单搜索",
|
||||
"menuAccordion": "侧边菜单手风琴模式",
|
||||
@ -73,7 +66,6 @@
|
||||
"menuCollapseButton": "菜单折叠按钮",
|
||||
"contentMode": "内容区域宽度",
|
||||
"expandedMenuWidth": "菜单展开宽度",
|
||||
|
||||
"breadcrumb": "面包屑",
|
||||
"breadcrumbIcon": "面包屑图标",
|
||||
"tabs": "标签页",
|
||||
@ -87,22 +79,17 @@
|
||||
"fullContent": "全屏内容",
|
||||
"grayMode": "灰色模式",
|
||||
"colorWeak": "色弱模式",
|
||||
|
||||
"progress": "顶部进度条",
|
||||
"switchLoading": "切换loading",
|
||||
"switchAnimation": "切换动画",
|
||||
"animationType": "动画类型",
|
||||
|
||||
"autoScreenLock": "自动锁屏",
|
||||
"notAutoScreenLock": "不自动锁屏",
|
||||
|
||||
"fixedHeader": "固定header",
|
||||
"fixedSideBar": "固定Sidebar",
|
||||
|
||||
"mixSidebarTrigger": "混合菜单触发方式",
|
||||
"triggerHover": "悬停",
|
||||
"triggerClick": "点击",
|
||||
|
||||
"mixSidebarFixed": "固定展开菜单"
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ dayjs.extend(timezone);
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(VueQueryPlugin);
|
||||
|
||||
function setupPlugins() {
|
||||
// 安装图标
|
||||
setupIcons();
|
||||
|
41
apps/platform/src/router/routes/modules/acl.ts
Normal file
41
apps/platform/src/router/routes/modules/acl.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_RENDERER_URL } from '@/constants';
|
||||
import { LOW_CODE_APPLICATION_ID, LOW_CODE_PROJECT_ID } from '@/constants/low-code';
|
||||
|
||||
const moduleName = 'acl';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/acl',
|
||||
name: moduleName,
|
||||
redirect: '/acl/list',
|
||||
meta: {
|
||||
title: '权限管理',
|
||||
icon: 'ant-design:user-outlined',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: `${moduleName}-list`,
|
||||
meta: {
|
||||
title: '权限列表',
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:list',
|
||||
app: {
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-project-list',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
applicationId: LOW_CODE_APPLICATION_ID,
|
||||
projectId: LOW_CODE_PROJECT_ID,
|
||||
fileId: '1hsd0407hf',
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
@ -1,4 +1,5 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_RENDERER_URL } from '@/constants';
|
||||
|
||||
// 微前端路由
|
||||
const moduleName = 'application';
|
||||
@ -20,11 +21,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:list',
|
||||
app: {
|
||||
url: 'https://localhost:10010',
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-application-list',
|
||||
sync: true,
|
||||
alive: true,
|
||||
degrade: true,
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
applicationId: 0,
|
||||
projectId: 4,
|
||||
fileId: 'b91n1y9yr',
|
||||
|
@ -4,4 +4,5 @@ import micro from './micro';
|
||||
import application from './application';
|
||||
import project from './project';
|
||||
import staticFile from './static-file';
|
||||
export default [...dashboard, ...user, ...micro, ...application, ...project, ...staticFile];
|
||||
import acl from './acl';
|
||||
export default [...dashboard, ...user, ...micro, ...application, ...project, ...staticFile, ...acl];
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_DESIGNER_URL, Y_CODE_V1_URL } from '@/constants';
|
||||
|
||||
// 微前端路由
|
||||
const moduleName = 'micro';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
@ -17,52 +17,36 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: `${moduleName}-designer`,
|
||||
meta: {
|
||||
title: '低代码编辑器',
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:edit-outlined',
|
||||
app: {
|
||||
url: 'https://localhost:10011',
|
||||
url: Y_CODE_DESIGNER_URL,
|
||||
name: 'y-code-designer',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/micro-container/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'renderer',
|
||||
name: `${moduleName}-renderer`,
|
||||
meta: {
|
||||
title: '低代码渲染器',
|
||||
keepAlive: true,
|
||||
// hideInMenu: true,
|
||||
icon: 'ant-design:eye-outlined',
|
||||
app: {
|
||||
url: 'https://localhost:10010',
|
||||
name: 'y-code-renderer',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
projectId: 4,
|
||||
sync: true,
|
||||
alive: true,
|
||||
degrade: true,
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/micro-container/index.vue'),
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'y-code-v1',
|
||||
name: `${moduleName}-y-code-v1`,
|
||||
meta: {
|
||||
title: '悦码 1.0',
|
||||
// keepAlive: true,
|
||||
keepAlive: true,
|
||||
// hideInMenu: true,
|
||||
icon: 'ant-design:delete-outlined',
|
||||
app: {
|
||||
url: 'http://localhost:10012',
|
||||
url: Y_CODE_V1_URL,
|
||||
name: 'y-code-v1',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
degrade: true,
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/micro-container/index.vue'),
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,4 +1,6 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_RENDERER_URL } from '@/constants';
|
||||
import { LOW_CODE_APPLICATION_ID, LOW_CODE_PROJECT_ID } from '@/constants/low-code';
|
||||
|
||||
// 微前端路由
|
||||
const moduleName = 'project';
|
||||
@ -20,18 +22,38 @@ const routes: Array<RouteRecordRaw> = [
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:list',
|
||||
app: {
|
||||
url: 'https://localhost:10010',
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-project-list',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
applicationId: 0,
|
||||
projectId: 4,
|
||||
applicationId: LOW_CODE_APPLICATION_ID,
|
||||
projectId: LOW_CODE_PROJECT_ID,
|
||||
fileId: '4g4mz6qi8u',
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'file',
|
||||
name: `${moduleName}-file`,
|
||||
meta: {
|
||||
title: 'dsl 文件列表',
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:file',
|
||||
app: {
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-project-file',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
applicationId: LOW_CODE_APPLICATION_ID,
|
||||
projectId: LOW_CODE_PROJECT_ID,
|
||||
fileId: '7pftwojzu',
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -1,4 +1,6 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_RENDERER_URL } from '@/constants';
|
||||
import { LOW_CODE_APPLICATION_ID, LOW_CODE_PROJECT_ID } from '@/constants/low-code';
|
||||
|
||||
// 微前端路由
|
||||
const moduleName = 'static-file';
|
||||
@ -9,7 +11,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: moduleName,
|
||||
meta: {
|
||||
title: '静态文件管理',
|
||||
icon: 'ant-design:file-outlined',
|
||||
icon: 'ant-design:file',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@ -18,13 +20,13 @@ const routes: Array<RouteRecordRaw> = [
|
||||
meta: {
|
||||
title: '静态文件列表',
|
||||
keepAlive: true,
|
||||
icon: 'ant-design:list',
|
||||
icon: 'ant-design:file',
|
||||
app: {
|
||||
url: 'https://localhost:10010',
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-application-list',
|
||||
sync: true,
|
||||
alive: true,
|
||||
degrade: true,
|
||||
applicationId: LOW_CODE_APPLICATION_ID,
|
||||
projectId: LOW_CODE_PROJECT_ID,
|
||||
fileId: '7pfr394d6',
|
||||
},
|
||||
},
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
|
@ -1,4 +1,6 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { Y_CODE_RENDERER_URL } from '@/constants';
|
||||
import { LOW_CODE_APPLICATION_ID, LOW_CODE_PROJECT_ID } from '@/constants/low-code';
|
||||
|
||||
const moduleName = 'user';
|
||||
|
||||
@ -17,55 +19,20 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: `${moduleName}-list`,
|
||||
meta: {
|
||||
title: '用户列表',
|
||||
icon: 'ant-design:unordered-list-outlined',
|
||||
keepAlive: true,
|
||||
hideInMenu: false,
|
||||
icon: 'ant-design:list',
|
||||
app: {
|
||||
url: Y_CODE_RENDERER_URL,
|
||||
name: 'y-code-platform-project-list',
|
||||
// sync: true,
|
||||
// alive: true,
|
||||
// degrade: true,
|
||||
applicationId: LOW_CODE_APPLICATION_ID,
|
||||
projectId: LOW_CODE_PROJECT_ID,
|
||||
fileId: 'b91ra0ej4',
|
||||
},
|
||||
},
|
||||
component: () => import('@/views/user/list.vue'),
|
||||
},
|
||||
{
|
||||
path: 'add',
|
||||
name: `${moduleName}-add`,
|
||||
meta: {
|
||||
title: '新增用户',
|
||||
icon: 'ant-design:user-add-outlined',
|
||||
hideInMenu: true,
|
||||
activeMenu: `${moduleName}-list`,
|
||||
},
|
||||
component: () => import('@/views/user/add.vue'),
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
name: `${moduleName}-edit`,
|
||||
meta: {
|
||||
title: '编辑用户',
|
||||
icon: 'ant-design:edit-outlined',
|
||||
hideInMenu: true,
|
||||
activeMenu: `${moduleName}-list`,
|
||||
},
|
||||
component: () => import('@/views/user/edit.vue'),
|
||||
},
|
||||
{
|
||||
path: 'detail/:id',
|
||||
name: `${moduleName}-detail`,
|
||||
meta: {
|
||||
title: '用户详情',
|
||||
icon: 'ant-design:profile-outlined',
|
||||
hideInMenu: true,
|
||||
activeMenu: `${moduleName}-list`,
|
||||
},
|
||||
component: () => import('@/views/user/detail.vue'),
|
||||
},
|
||||
{
|
||||
path: 'change-password/:id',
|
||||
name: `${moduleName}-change-password`,
|
||||
meta: {
|
||||
title: '修改密码',
|
||||
icon: 'ant-design:lock-outlined',
|
||||
hideInMenu: true,
|
||||
activeMenu: `${moduleName}-list`,
|
||||
},
|
||||
component: () => import('@/views/user/change-password.vue'),
|
||||
component: () => import('@/components/renderer-adapter/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,16 +1,16 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { LOGIN_NAME } from '@/router/constant';
|
||||
// import type { RouteRecordRaw } from 'vue-router';
|
||||
// import { LOGIN_NAME } from '@/router/constant';
|
||||
|
||||
/**
|
||||
* layout布局之外的路由
|
||||
*/
|
||||
export const LoginRoute: RouteRecordRaw = {
|
||||
path: '/login',
|
||||
name: LOGIN_NAME,
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
meta: {
|
||||
title: '登录',
|
||||
},
|
||||
};
|
||||
// export const LoginRoute: RouteRecordRaw = {
|
||||
// path: '/login',
|
||||
// name: LOGIN_NAME,
|
||||
// component: () => import('@/views/login/index.vue'),
|
||||
// meta: {
|
||||
// title: '登录',
|
||||
// },
|
||||
// };
|
||||
|
||||
export default [LoginRoute];
|
||||
export default [];
|
||||
|
0
apps/platform/src/store/modules/application.ts
Normal file
0
apps/platform/src/store/modules/application.ts
Normal file
@ -5,8 +5,7 @@ interface KeepAliveState {
|
||||
list: string[];
|
||||
}
|
||||
|
||||
export const useKeepAliveStore = defineStore({
|
||||
id: 'keep-alive',
|
||||
export const useKeepAliveStore = defineStore('keep-alive', {
|
||||
state: (): KeepAliveState => ({
|
||||
list: [],
|
||||
}),
|
||||
|
0
apps/platform/src/store/modules/project.ts
Normal file
0
apps/platform/src/store/modules/project.ts
Normal file
@ -3,7 +3,8 @@ import { defineStore } from 'pinia';
|
||||
import { useSSEStore } from './sse';
|
||||
import { store } from '@/store';
|
||||
import { resetRouter } from '@/router';
|
||||
import { login, logout } from '@/io';
|
||||
import tianti from '@/io/tianti';
|
||||
import { getCurrentUser } from '@/io/user';
|
||||
|
||||
export const useUserStore = defineStore(
|
||||
'user',
|
||||
@ -13,6 +14,10 @@ export const useUserStore = defineStore(
|
||||
const perms = ref<string[]>([]);
|
||||
const userInfo = ref<Partial<API.UserEntity>>({});
|
||||
|
||||
const setToken = (_token: string) => {
|
||||
token.value = _token;
|
||||
};
|
||||
|
||||
/** 清空登录态(token、userInfo...) */
|
||||
const clearLoginStatus = () => {
|
||||
token.value = '';
|
||||
@ -23,21 +28,24 @@ export const useUserStore = defineStore(
|
||||
localStorage.clear();
|
||||
});
|
||||
};
|
||||
/** 登录成功保存token */
|
||||
const setToken = (_token: string) => {
|
||||
token.value = _token;
|
||||
};
|
||||
/** 登录 */
|
||||
const login = async (params: any) => {
|
||||
const data = await login(params);
|
||||
console.log('data', data);
|
||||
// @ts-ignore
|
||||
setToken(data.msg);
|
||||
const login = async () => {
|
||||
tianti.checkQuery();
|
||||
const token = localStorage.getItem('y-code-access-token');
|
||||
if (token) {
|
||||
setToken(token);
|
||||
setTimeout(() => {
|
||||
getCurrentUser().then((res) => {
|
||||
userInfo.value = res.data.data;
|
||||
console.log('userInfo', userInfo.value);
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
/** 登出 */
|
||||
const logout = async () => {
|
||||
sseStore.closeEventSource();
|
||||
await logout();
|
||||
await tianti.logout();
|
||||
clearLoginStatus();
|
||||
};
|
||||
|
||||
|
28
apps/platform/src/views/error/403.vue
Normal file
28
apps/platform/src/views/error/403.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<script lang="jsx">
|
||||
import { defineComponent } from 'vue';
|
||||
import OneClickAuth from '@sy/unified-login/one-click-auth.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ForbiddenPage',
|
||||
|
||||
setup() {
|
||||
return () => {
|
||||
return (
|
||||
<div class="forbidden-page">
|
||||
<OneClickAuth env="dev" appMark={30} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.forbidden-page {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<div>1</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.login-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding-top: 240px;
|
||||
background: url('@/assets/login.svg');
|
||||
background-size: 100%;
|
||||
|
||||
.login-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.svg-icon {
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-form) {
|
||||
width: 400px;
|
||||
|
||||
.ant-col {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ant-form-item-label {
|
||||
padding-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-type-switch {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<div class="add-user">
|
||||
<a-card :bordered="false">
|
||||
<a-form layout="vertical" :model="userForm" @submit="handleAddUser">
|
||||
<a-form-item label="用户名">
|
||||
<a-input
|
||||
v-model:value="userForm.username"
|
||||
placeholder="请输入用户名"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input
|
||||
v-model:value="userForm.password"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">新增用户</a-button>
|
||||
<a-button @click="goBack">取消</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
||||
const { closeCurrentTab } = useTabsViewStore();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
// 用户表单数据
|
||||
const userForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
});
|
||||
|
||||
// 新增用户
|
||||
const handleAddUser = async () => {
|
||||
// TODO: 调用新增用户接口
|
||||
message.success('用户新增成功');
|
||||
goBack();
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
router.back();
|
||||
closeCurrentTab(route);
|
||||
};
|
||||
</script>
|
@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="change-password">
|
||||
<a-card :bordered="false">
|
||||
<a-form layout="vertical" :model="passwordForm" @submit="handleChangePassword">
|
||||
<a-form-item label="新密码">
|
||||
<a-input
|
||||
v-model:value="passwordForm.newPassword"
|
||||
placeholder="请输入新密码"
|
||||
type="password"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码">
|
||||
<a-input
|
||||
v-model:value="passwordForm.confirmPassword"
|
||||
placeholder="请确认新密码"
|
||||
type="password"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">修改密码</a-button>
|
||||
<a-button type="default" @click="goBack">取消</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
||||
const { closeCurrentTab } = useTabsViewStore();
|
||||
|
||||
const router = useRouter();
|
||||
console.log('router', router);
|
||||
const route = useRoute();
|
||||
|
||||
// 密码表单数据
|
||||
const passwordForm = reactive({
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
|
||||
// 修改密码
|
||||
const handleChangePassword = async () => {
|
||||
if (passwordForm.newPassword !== passwordForm.confirmPassword) {
|
||||
message.error('两次输入的密码不一致');
|
||||
return;
|
||||
}
|
||||
// TODO: 调用修改密码接口
|
||||
message.success('密码修改成功');
|
||||
goBack();
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
router.back();
|
||||
closeCurrentTab(route);
|
||||
};
|
||||
</script>
|
@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<div class="user-detail">
|
||||
<a-card title="用户详情" :bordered="false">
|
||||
<!-- 基本信息 -->
|
||||
<a-descriptions bordered>
|
||||
<a-descriptions-item label="用户名">
|
||||
{{ userInfo.username }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="昵称">
|
||||
{{ userInfo.nickname }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="手机号">
|
||||
{{ userInfo.phone }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="邮箱">
|
||||
{{ userInfo.email }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">
|
||||
<a-tag :color="userInfo.status === 1 ? 'green' : 'red'">
|
||||
{{ userInfo.status === 1 ? '启用' : '禁用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">
|
||||
{{ userInfo.createTime }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="operation-buttons" style="margin-top: 24px">
|
||||
<a-button type="primary" @click="handleEdit">编辑</a-button>
|
||||
<a-button style="margin-left: 8px" @click="goBack">返回</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
||||
const { closeCurrentTab } = useTabsViewStore();
|
||||
|
||||
const userInfo = ref({
|
||||
username: 'mockUser',
|
||||
nickname: 'mockNickname',
|
||||
phone: '1234567890',
|
||||
email: 'mock@example.com',
|
||||
status: 1,
|
||||
createTime: '2023-01-01 12:00:00',
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
getUserDetail();
|
||||
});
|
||||
|
||||
// 获取用户详情
|
||||
async function getUserDetail() {
|
||||
try {
|
||||
const userId = route.params.id;
|
||||
// 这里替换成实际的 API 调用
|
||||
const response = await $api.user.getDetail(userId);
|
||||
userInfo.value = response.data;
|
||||
} catch (err) {
|
||||
console.error('err', err);
|
||||
$message.error('获取用户详情失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑用户
|
||||
function handleEdit() {
|
||||
const userId = route.params.id;
|
||||
router.push(`/user/edit/${userId}`);
|
||||
}
|
||||
|
||||
// 返回上一页并关闭当前标签
|
||||
function goBack() {
|
||||
router.back();
|
||||
closeCurrentTab(route);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-detail {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
|
||||
.operation-buttons {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,106 +0,0 @@
|
||||
<template>
|
||||
<div class="user-edit">
|
||||
<a-card :bordered="false">
|
||||
<a-form layout="vertical" :model="userForm" @submit="handleSave">
|
||||
<a-form-item label="用户名">
|
||||
<a-input
|
||||
v-model:value="userForm.username"
|
||||
placeholder="请输入用户名"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="昵称">
|
||||
<a-input
|
||||
v-model:value="userForm.nickname"
|
||||
placeholder="请输入昵称"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="手机号">
|
||||
<a-input
|
||||
v-model:value="userForm.phone"
|
||||
placeholder="请输入手机号"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="邮箱">
|
||||
<a-input
|
||||
v-model:value="userForm.email"
|
||||
placeholder="请输入邮箱"
|
||||
allow-clear
|
||||
style="max-width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态">
|
||||
<a-select v-model:value="userForm.status" style="max-width: 400px">
|
||||
<a-select-option :value="1">启用</a-select-option>
|
||||
<a-select-option :value="0">禁用</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">保存</a-button>
|
||||
<a-button @click="goBack">取消</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { closeCurrentTab } = useTabsViewStore();
|
||||
|
||||
// 用户信息表单数据
|
||||
const userForm = ref({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
status: 1,
|
||||
});
|
||||
|
||||
// 保存用户信息
|
||||
const handleSave = async () => {
|
||||
// TODO: 调用保存接口
|
||||
message.success('保存成功');
|
||||
goBack();
|
||||
};
|
||||
|
||||
// 取消编辑
|
||||
const goBack = () => {
|
||||
router.back(); // 假设返回用户列表页面
|
||||
closeCurrentTab(route); // 关闭当前标签页
|
||||
};
|
||||
|
||||
// 初始化用户信息(可以通过接口获取)
|
||||
const initUserData = async (userId: string) => {
|
||||
// TODO: 调用接口获取用户信息
|
||||
// const res = await getUserInfo(userId);
|
||||
|
||||
// 添加 mock 数据
|
||||
userForm.value = {
|
||||
username: 'mockUser',
|
||||
nickname: 'mockNickname',
|
||||
phone: '1234567890',
|
||||
email: 'mock@example.com',
|
||||
status: 1,
|
||||
};
|
||||
};
|
||||
|
||||
// 获取用户ID并初始化数据
|
||||
const userId = route.params.id; // 假设路由中有用户ID
|
||||
if (userId) {
|
||||
initUserData(userId);
|
||||
}
|
||||
</script>
|
@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<div class="user-list">
|
||||
<a-card :bordered="false">
|
||||
<!-- 搜索区域 -->
|
||||
<a-form layout="inline" :model="searchForm" @submit="handleSearch">
|
||||
<a-form-item label="用户名" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||
<a-input v-model:value="searchForm.username" placeholder="请输入用户名" allow-clear />
|
||||
</a-form-item>
|
||||
<a-form-item label="手机号" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||
<a-input v-model:value="searchForm.phone" placeholder="请输入手机号" allow-clear />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">查询</a-button>
|
||||
<a-button @click="resetSearch">重置</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="table-operations">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
新增用户
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:row-selection="{ selectedRowKeys, onChange: onSelectChange }"
|
||||
row-key="id"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<!-- 状态列 -->
|
||||
<template #status="{ text }">
|
||||
<a-tag :color="text ? 'success' : 'error'">
|
||||
{{ text ? '启用' : '禁用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<template #action="{ record }">
|
||||
<a-space>
|
||||
<a-button type="link" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="link" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="link" @click="handleChangePassword(record)">修改密码</a-button>
|
||||
<a-popconfirm title="确定要删除这条记录吗?" @confirm="handleDelete(record)">
|
||||
<a-button type="link" danger>删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索表单数据
|
||||
const searchForm = reactive({
|
||||
username: '',
|
||||
phone: '',
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'username',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '昵称',
|
||||
dataIndex: 'nickname',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
dataIndex: 'phone',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 100,
|
||||
slots: { customRender: 'status' },
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
width: 280,
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
];
|
||||
|
||||
// 表格数据
|
||||
const loading = ref(false);
|
||||
const tableData = ref<any[]>([]);
|
||||
const selectedRowKeys = ref<string[]>([]);
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
});
|
||||
|
||||
// 获取表格数据
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
// TODO: 调用接口获取数据
|
||||
// const res = await getUserList({
|
||||
// ...searchForm,
|
||||
// page: pagination.current,
|
||||
// pageSize: pagination.pageSize,
|
||||
// });
|
||||
// tableData.value = res.data.list;
|
||||
// pagination.total = res.data.total;
|
||||
|
||||
// 模拟数据
|
||||
tableData.value = Array.from({ length: 10 }).map((_, index) => ({
|
||||
id: index + 1,
|
||||
username: `user${index + 1}`,
|
||||
nickname: `用户${index + 1}`,
|
||||
phone: '13800138000',
|
||||
email: `user${index + 1}@example.com`,
|
||||
status: index % 2,
|
||||
createTime: '2024-03-20 12:00:00',
|
||||
}));
|
||||
pagination.total = 100;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 表格选择改变
|
||||
const onSelectChange = (keys: string[]) => {
|
||||
selectedRowKeys.value = keys;
|
||||
};
|
||||
|
||||
// 表格分页、排序、筛选变化
|
||||
const handleTableChange = (pag: any) => {
|
||||
pagination.current = pag.current;
|
||||
pagination.pageSize = pag.pageSize;
|
||||
getTableData();
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1;
|
||||
getTableData();
|
||||
};
|
||||
|
||||
// 重置搜索
|
||||
const resetSearch = () => {
|
||||
searchForm.username = '';
|
||||
searchForm.phone = '';
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
// 新增用户
|
||||
const handleAdd = () => {
|
||||
router.push('/user/add');
|
||||
};
|
||||
|
||||
// 编辑用户
|
||||
const handleEdit = (record: any) => {
|
||||
router.push(`/user/edit/${record.id}`);
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (record: any) => {
|
||||
router.push(`/user/detail/${record.id}`);
|
||||
};
|
||||
|
||||
// 修改密码
|
||||
const handleChangePassword = (record: any) => {
|
||||
router.push(`/user/change-password/${record.id}`);
|
||||
};
|
||||
|
||||
// 删除用户
|
||||
const handleDelete = async (record: any) => {
|
||||
// TODO: 调用删除接口
|
||||
message.success('删除成功');
|
||||
getTableData();
|
||||
};
|
||||
|
||||
// 初始化
|
||||
getTableData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-list {
|
||||
.table-operations {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -32,7 +32,7 @@
|
||||
"strictFunctionTypes": false,
|
||||
"noImplicitAny": false,
|
||||
"lib": ["dom", "esnext", "DOM.Iterable"],
|
||||
"types": ["node", "vite/client"],
|
||||
"types": ["node", "vite/client", "vue"],
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
|
1
apps/platform/types/shims/shims-vue.d.ts
vendored
1
apps/platform/types/shims/shims-vue.d.ts
vendored
@ -14,6 +14,7 @@ declare module 'vue' {
|
||||
Reflect: Reflect;
|
||||
suspenseStatus: '' | 'pending' | 'resolve' | 'fallback';
|
||||
}
|
||||
export * from '@vue/runtime-core';
|
||||
}
|
||||
|
||||
declare type Nullable<T> = T | null;
|
||||
|
@ -26,7 +26,8 @@ const __APP_INFO__ = {
|
||||
export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
console.log('mode', mode);
|
||||
// 环境变量
|
||||
const env = loadEnv(mode, process.cwd(), ['VITE_', 'VTJ_', 'SY_']);
|
||||
const env = loadEnv(mode, process.cwd(), ['VITE_', 'VTJ_', 'SY_', 'Y_CODE_']);
|
||||
console.log('env', env);
|
||||
const isDev = command === 'serve';
|
||||
|
||||
return {
|
||||
@ -46,6 +47,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
server: {
|
||||
open: true,
|
||||
host: true,
|
||||
cors: true,
|
||||
port: Number(env.VITE_PORT),
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'https://custom-chart-pre-api.shiyue.com',
|
||||
|
@ -5,9 +5,13 @@ VITE_NODE_ENV = 'development'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# 前端可见变量(必须以 VITE_ 开头)
|
||||
VITE_PORT = 10010
|
||||
VITE_PORT = 10012
|
||||
# VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
|
||||
|
||||
VITE_DEBUG_MODE = true
|
||||
VITE_DEBUG_MODE = true
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://localhost:10010/'
|
||||
Y_CODE_DESIGNER_URL = 'https://localhost:10011/'
|
||||
Y_CODE_RENDERER_URL = 'https://localhost:10012/'
|
@ -5,3 +5,7 @@ VITE_NODE_ENV = 'production'
|
||||
VITE_BASE_URL = /
|
||||
|
||||
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/'
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform.shiyuegame.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer.shiyuegame.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer.shiyuegame.com/'
|
||||
|
@ -8,4 +8,8 @@ VITE_BASE_URL = /
|
||||
VITE_PORT = 10010
|
||||
|
||||
# base api url
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
|
||||
|
||||
Y_CODE_PLATFORM_URL = 'https://y-code-platform-pre.shiyue.com/'
|
||||
Y_CODE_DESIGNER_URL = 'https://y-code-designer-pre.shiyue.com/'
|
||||
Y_CODE_RENDERER_URL = 'https://y-code-renderer-pre.shiyue.com/'
|
@ -7,7 +7,7 @@ import path from "path";
|
||||
// @ts-ignore
|
||||
export default defineConfig(({ mode }) => {
|
||||
console.log("mode", mode);
|
||||
const env = loadEnv(mode, process.cwd(), ["VITE_"]);
|
||||
const env = loadEnv(mode, process.cwd(), ["VITE_", "Y_CODE_"]);
|
||||
|
||||
return {
|
||||
server: {
|
||||
|
@ -18,13 +18,14 @@
|
||||
"@sy/low-code-shared": "workspace:*",
|
||||
"@sy/web-vitals": "workspace:*",
|
||||
"@tanstack/vue-query": "^5.66.9",
|
||||
"@vtj/core": "^0.10.9",
|
||||
"@vtj/icons": "0.10.9",
|
||||
"@vtj/materials": "^0.10.9",
|
||||
"@vtj/pro": "^0.10.9",
|
||||
"@vtj/renderer": "^0.10.9",
|
||||
"@vtj/ui": "^0.10.9",
|
||||
"@vtj/web": "^0.10.9",
|
||||
"@vtj/core": "^0.10.10",
|
||||
"@vtj/icons": "0.10.10",
|
||||
"@vtj/materials": "^0.10.10",
|
||||
"@vtj/pro": "^0.10.10",
|
||||
"@vtj/renderer": "^0.10.10",
|
||||
"@vtj/ui": "^0.10.10",
|
||||
"@vtj/utils": "^0.10.10",
|
||||
"@vtj/web": "^0.10.10",
|
||||
"axios": "^1.8.1",
|
||||
"core-js": "^3.40.0",
|
||||
"element-plus": "^2.9.4",
|
||||
@ -35,10 +36,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@farmfe/cli": "^1.0.4",
|
||||
"@vtj/cli": "^0.10.2",
|
||||
"@farmfe/core": "^1.6.6",
|
||||
"@sy/vite-plugin-http2-proxy": "workspace:*",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vtj/cli": "^0.10.2",
|
||||
"vite-plugin-mkcert": "^1.17.6"
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import { createProvider } from '@vtj/web'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { LowCodeService } from './service'
|
||||
import { getFile } from './io'
|
||||
import { request, jsonp } from '@vtj/utils'
|
||||
// import * as VtjUI from '@vtj/ui'
|
||||
|
||||
// 响应式状态
|
||||
@ -13,7 +14,11 @@ const renderer = ref()
|
||||
const lowCodeService = new LowCodeService()
|
||||
|
||||
// Postmate 握手协议
|
||||
const handshake = new Postmate.Model({})
|
||||
const postmate = new Postmate.Model({
|
||||
sayHi: (data: any) => {
|
||||
console.log('sayHi',data)
|
||||
}
|
||||
})
|
||||
|
||||
// 数据模型
|
||||
const model = {
|
||||
@ -21,28 +26,33 @@ const model = {
|
||||
applicationId: -1,
|
||||
projectId: -1,
|
||||
fileId: '',
|
||||
url: ''
|
||||
url: '',
|
||||
accessToken: ''
|
||||
}
|
||||
|
||||
// 数据查询
|
||||
const { data: file, isFetching } = useQuery({
|
||||
queryKey: ['getFile'],
|
||||
queryFn: async () => {
|
||||
await handshake.then((parent) => {
|
||||
// parent.emit('sync-context', 'Hello, World!')
|
||||
await postmate.then((parent) => {
|
||||
parent.emit('some-event', 'y-code-renderer is ready')
|
||||
Object.assign(model, parent.model)
|
||||
|
||||
// console.log('model', model)
|
||||
localStorage.setItem('y-code-access-token', model.accessToken || '')
|
||||
})
|
||||
|
||||
return getFile(model.fileId).then(() => {
|
||||
request.useRequest((req) => {
|
||||
req.headers.set('Authorization', `Bearer ${model.accessToken}`)
|
||||
return req
|
||||
})
|
||||
const { provider, onReady } = createProvider({
|
||||
nodeEnv: import.meta.env.NODE_ENV,
|
||||
service: lowCodeService,
|
||||
project: { id: model.projectId },
|
||||
// components: {
|
||||
// ...VtjUI,
|
||||
// }
|
||||
adapter: {
|
||||
request,
|
||||
jsonp
|
||||
}
|
||||
})
|
||||
onReady(async () => {
|
||||
const instance = getCurrentInstance()
|
||||
|
2
apps/renderer/src/constants/env.ts
Normal file
2
apps/renderer/src/constants/env.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// @ts-ignore
|
||||
export const currentEnv = __APP_ENV__;
|
1
apps/renderer/src/constants/index.ts
Normal file
1
apps/renderer/src/constants/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./env";
|
@ -12,7 +12,6 @@ const app = createApp(App);
|
||||
|
||||
// 批量注册组件
|
||||
Object.entries(VtjUI).forEach(([name, component]) => {
|
||||
console.log("name", name, component);
|
||||
app.component(name, component);
|
||||
});
|
||||
app
|
||||
|
@ -1,7 +1,7 @@
|
||||
# .env.development
|
||||
VITE_NODE_ENV = development
|
||||
|
||||
VITE_PORT = 10012
|
||||
VITE_PORT = 10013
|
||||
|
||||
VITE_OA_BASEURL = https://oa-pre.shiyue.com
|
||||
|
||||
|
@ -43,11 +43,11 @@
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"less": "^4.2.2",
|
||||
"semantic-release": "^24.2.2",
|
||||
"typescript": "~5.3.3",
|
||||
"typescript": "~5.8.2",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-qiankun": "^1.0.15",
|
||||
"vue-tsc": "^2.2.0",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.4.1"
|
||||
|
15
package.json
15
package.json
@ -13,7 +13,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"low-code:help": "node ./scripts/index.mjs",
|
||||
"preinstall": "npx only-allow pnpm && pnpm i -g turbo rimraf",
|
||||
"preinstall": "npx only-allow pnpm && pnpm i -g turbo rimraf cross-env",
|
||||
"dev": "turbo run dev",
|
||||
"build": "turbo run build",
|
||||
"preview": "turbo run preview",
|
||||
@ -38,7 +38,9 @@
|
||||
"eslint-plugin-prettier": "~5.2.3",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"husky": "~9.1.7",
|
||||
"inquirer": "^12.4.2",
|
||||
"lint-staged": "~15.2.11",
|
||||
"ora": "^8.2.0",
|
||||
"postcss-html": "~1.7.0",
|
||||
"prettier": "~3.3.3",
|
||||
"stylelint": "~16.10.0",
|
||||
@ -48,11 +50,8 @@
|
||||
"stylelint-config-standard": "~36.0.1",
|
||||
"stylelint-order": "~6.0.4",
|
||||
"stylelint-prettier": "^5.0.3",
|
||||
"typescript": "~5.6.3",
|
||||
"vue-eslint-parser": "~9.4.3",
|
||||
"vue-tsc": "~2.1.10",
|
||||
"inquirer": "^12.4.2",
|
||||
"ora": "^8.2.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
"typescript": "~5.8.2",
|
||||
"vue-eslint-parser": "~10.1.1",
|
||||
"vue-tsc": "~2.2.8"
|
||||
}
|
||||
}
|
@ -16,6 +16,6 @@
|
||||
"clean": "rimraf node_modules"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.7.3"
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
1644
pnpm-lock.yaml
generated
1644
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user