Compare commits

..

10 Commits

Author SHA1 Message Date
wangxuefeng
99015ecbd2 chore: 更新底层引擎 2025-03-07 21:01:56 +08:00
wangxuefeng
db10bb6a6c feat: 设计器可获取天梯 token 2025-03-07 14:46:22 +08:00
wangxuefeng
8d0c890061 chore: 剔除跟登陆相关的无用逻辑 2025-03-07 10:08:16 +08:00
wangxuefeng
9d25cddcb3 feat: 用户通过天梯登陆 2025-03-07 10:06:58 +08:00
wangxuefeng
0852dd98f0 chore: 完成天梯登陆与登出 2025-03-06 17:58:47 +08:00
wangxuefeng
9b2c728d4c chore: 悦码v1增加环境配置 2025-03-06 10:28:14 +08:00
wangxuefeng
eecc2b1893 chore: 规范化常量配置 2025-03-05 18:30:41 +08:00
wangxuefeng
261dd5bb67 chore: 增加环境配置 2025-03-05 18:03:59 +08:00
wangxuefeng
47c9ec1aba feat: platform 接入天梯登陆的 依赖 2025-03-05 17:55:51 +08:00
wangxuefeng
dd69823a00 feat: 可通过配置入参来初始化编辑器 2025-03-05 14:34:40 +08:00
66 changed files with 1375 additions and 1856 deletions

View File

@ -9,3 +9,9 @@ VITE_PORT = 10011
# VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/' # VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.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/'

View File

@ -5,3 +5,8 @@ VITE_NODE_ENV = 'production'
VITE_BASE_URL = / VITE_BASE_URL = /
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/' 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/'

View File

@ -6,3 +6,7 @@ VITE_BASE_URL = /
# base api 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/'

View File

@ -13,22 +13,23 @@
"clean": "rimraf node_modules" "clean": "rimraf node_modules"
}, },
"dependencies": { "dependencies": {
"@vtj/core": "^0.10.9", "@vtj/core": "^0.10.10",
"@vtj/designer": "0.10.9", "@vtj/designer": "0.10.10",
"@vtj/icons": "0.10.9", "@vtj/icons": "0.10.10",
"@vtj/local": "^0.10.9", "@vtj/local": "^0.10.10",
"@vtj/materials": "^0.10.9", "@vtj/materials": "^0.10.10",
"@vtj/node": "0.10.2", "@vtj/node": "0.10.2",
"@vtj/pro": "^0.10.9", "@vtj/pro": "^0.10.10",
"@vtj/renderer": "^0.10.9", "@vtj/renderer": "^0.10.10",
"@vtj/ui": "^0.10.9", "@vtj/ui": "^0.10.10",
"@vtj/utils": "0.10.9", "@vtj/utils": "0.10.10",
"@vtj/web": "^0.10.9", "@vtj/web": "^0.10.10",
"axios": "^1.8.1", "axios": "^1.8.1",
"element-plus": "^2.9.4", "element-plus": "^2.9.4",
"licia-es": "^1.46.0", "licia-es": "^1.46.0",
"pinia": "^3.0.1", "pinia": "^3.0.1",
"pinia-plugin-persistedstate": "^4.2.0", "pinia-plugin-persistedstate": "^4.2.0",
"postmate": "^1.5.2",
"unplugin-auto-import": "^19.1.1", "unplugin-auto-import": "^19.1.1",
"vue": "~3.5.13", "vue": "~3.5.13",
"vue-router": "~4.5.0" "vue-router": "~4.5.0"

View File

@ -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>

View File

@ -0,0 +1,2 @@
// @ts-ignore
export const currentEnv = __APP_ENV__;

View File

@ -0,0 +1 @@
export * from './env';

View File

@ -1,7 +1,6 @@
import axios from 'axios'; import axios from 'axios';
const apiBase = import.meta.env.VITE_BASE_API_URL; const apiBase = import.meta.env.VITE_BASE_API_URL;
console.log('apiBase', apiBase);
// 创建独立实例 // 创建独立实例
const instance = axios.create({ const instance = axios.create({

View File

@ -8,7 +8,7 @@ export const pinia = createPinia();
// 用户模块 store // 用户模块 store
export const useUserStore = defineStore('user', () => { 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); const userProfile = ref<null>(null);
// getter 计算属性 // getter 计算属性
@ -17,20 +17,14 @@ export const useUserStore = defineStore('user', () => {
// 同步 action // 同步 action
const setToken = (newToken: string) => { const setToken = (newToken: string) => {
token.value = newToken; token.value = newToken;
localStorage.setItem('token', newToken); localStorage.setItem('y-code-access-token', newToken);
};
// 异步 action
const fetchProfile = async () => {
const { data } = await axios.get('/api/user/profile');
userProfile.value = data;
}; };
// 清理方法 // 清理方法
const logout = () => { const logout = () => {
token.value = ''; token.value = '';
userProfile.value = null; userProfile.value = null;
localStorage.removeItem('token'); localStorage.removeItem('y-code-access-token');
}; };
return { return {
@ -38,7 +32,6 @@ export const useUserStore = defineStore('user', () => {
userProfile, userProfile,
isLoggedIn, isLoggedIn,
setToken, setToken,
fetchProfile,
logout logout
}; };
}); });

View File

@ -1,40 +1,71 @@
<template>
<div class="designer-container" ref="container"></div>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { import Postmate from 'postmate';
Engine, import { Engine, widgetManager } from '@vtj/pro';
widgetManager import { request, jsonp } from '@vtj/utils';
// type ProjectModel import { useUserStore } from '@/store';
} from '@vtj/pro';
import { LowCodeService } from '@/service'; import { LowCodeService } from '@/service';
const container = ref(); const container = ref();
const service = new LowCodeService(); const service = new LowCodeService();
const userStore = useUserStore();
const engine = new Engine({ onMounted(async () => {
container, //
service, const model = {
project: { name: '',
// @ts-ignore url: '',
id: 4, applicationId: -1,
name: '低代码平台' projectId: -1,
} accessToken: ''
}); };
widgetManager.set('Previewer', { const handshake = new Postmate.Model({});
props: { await handshake.then((parent) => {
path: (block: any) => { parent.emit('sync-context', 'y-code-designer is ready');
const pathname = location.pathname; Object.assign(model, parent.model);
return `${pathname}#/preview/${block.id}`; // 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> </script>
<template>
<div
class="designer-container"
ref="container"
:token="userStore.token"></div>
</template>
<style scoped> <style scoped>
.designer-container { .designer-container {
height: 100%; height: 100%;

View File

@ -1,12 +1,20 @@
<template> <template>
<component v-if="renderer" :is="renderer"></component> <component v-if="renderer" :is="renderer" v-bind="$attrs"></component>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, getCurrentInstance } from 'vue'; import { ref, getCurrentInstance } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { createProvider, ContextMode } from '@vtj/pro'; import { createProvider, ContextMode } from '@vtj/pro';
import { LowCodeService } from '@/service'; import { LowCodeService } from '@/service';
import { request, jsonp } from '@vtj/utils';
import { useUserStore } from '@/store';
const userStore = useUserStore();
const service = new LowCodeService(); const service = new LowCodeService();
request.useRequest((req) => {
req.headers.set('Authorization', `Bearer ${userStore.token}`);
return req;
});
const { provider, onReady } = createProvider({ const { provider, onReady } = createProvider({
mode: ContextMode.Runtime, mode: ContextMode.Runtime,
service, service,
@ -14,6 +22,10 @@ const { provider, onReady } = createProvider({
// @ts-ignore // @ts-ignore
id: 4 id: 4
}, },
adapter: {
request,
jsonp
},
dependencies: { dependencies: {
Vue: () => import('vue'), Vue: () => import('vue'),
VueRouter: () => import('vue-router'), VueRouter: () => import('vue-router'),

View File

@ -35,7 +35,7 @@ const config = createViteConfig({
export default defineConfig(({ mode }) => { export default defineConfig(({ mode }) => {
console.log('mode', mode); console.log('mode', mode);
// 加载环境变量(支持 .env.development/.env.production // 加载环境变量(支持 .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 { return {
...config, ...config,
server: { server: {

View File

@ -6,6 +6,13 @@ VITE_BASE_URL = /
# 前端可见变量(必须以 VITE_ 开头) # 前端可见变量(必须以 VITE_ 开头)
VITE_PORT = 10010 VITE_PORT = 10010
# VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/' VITE_BASE_API_URL = 'https://custom-chart-pre-api.shiyue.com/'
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.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/'
Y_CODE_V1_URL = 'https://localhost:10013/'

View File

@ -5,3 +5,8 @@ VITE_NODE_ENV = 'production'
VITE_BASE_URL = / VITE_BASE_URL = /
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/' 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/'

View File

@ -6,3 +6,8 @@ VITE_BASE_URL = /
# base api 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/'

View File

@ -1,42 +1,3 @@
## 安装使用 # 因为项目接入了天梯登陆,使用前需要申请天梯的悦码权限
- 安装依赖 天梯地址 https://auth-pro.shiyue.com/
```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` 开发中

View File

@ -29,9 +29,11 @@
"@ant-design/icons-vue": "~7.0.1", "@ant-design/icons-vue": "~7.0.1",
"@iconify/vue": "^4.3.0", "@iconify/vue": "^4.3.0",
"@iframe-resizer/parent": "^5.3.3", "@iframe-resizer/parent": "^5.3.3",
"@sy/unified-login": "1.0.29",
"@sy/y-code-renderer-adapter": "workspace:*", "@sy/y-code-renderer-adapter": "workspace:*",
"@tanstack/query-core": "^5.66.4", "@tanstack/query-core": "^5.66.4",
"@tanstack/vue-query": "^5.66.9", "@tanstack/vue-query": "^5.66.9",
"@vue/runtime-core": "^3.5.13",
"@vueuse/core": "~11.1.0", "@vueuse/core": "~11.1.0",
"ant-design-vue": "~4.2.6", "ant-design-vue": "~4.2.6",
"axios": "~1.8.1", "axios": "~1.8.1",
@ -51,9 +53,9 @@
"vue": "~3.5.13", "vue": "~3.5.13",
"vue-i18n": "^11.1.1", "vue-i18n": "^11.1.1",
"vue-router": "~4.4.5", "vue-router": "~4.4.5",
"vue-types": "~5.1.3", "vue-types": "~6.0.0",
"vue-virtual-scroller": "2.0.0-beta.8", "vue-virtual-scroller": "2.0.0-beta.8",
"wujie": "^1.0.25", "wujie-vue3": "^1.0.25",
"xlsx": "~0.18.5" "xlsx": "~0.18.5"
}, },
"devDependencies": { "devDependencies": {
@ -62,9 +64,9 @@
"@iconify-json/ant-design": "^1.2.5", "@iconify-json/ant-design": "^1.2.5",
"@iconify-json/ep": "^1.2.2", "@iconify-json/ep": "^1.2.2",
"@iconify/json": "^2.2.307", "@iconify/json": "^2.2.307",
"@sy/y-code-designer": "workspace:*",
"@sy/low-code-shared": "workspace:*", "@sy/low-code-shared": "workspace:*",
"@sy/vite-plugin-http2-proxy": "workspace:*", "@sy/vite-plugin-http2-proxy": "workspace:*",
"@sy/y-code-designer": "workspace:*",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@types/lodash-es": "~4.17.12", "@types/lodash-es": "~4.17.12",
"@types/node": "~22.7.9", "@types/node": "~22.7.9",
@ -74,8 +76,8 @@
"@typescript-eslint/parser": "~8.11.0", "@typescript-eslint/parser": "~8.11.0",
"@umijs/openapi": "^1.13.0", "@umijs/openapi": "^1.13.0",
"@vitejs/plugin-vue": "~5.1.5", "@vitejs/plugin-vue": "~5.1.5",
"@vitejs/plugin-vue-jsx": "~4.0.1", "@vitejs/plugin-vue-jsx": "~4.1.1",
"@vue/tsconfig": "^0.5.1", "@vue/tsconfig": "^0.7.0",
"commitizen": "~4.3.1", "commitizen": "~4.3.1",
"conventional-changelog-cli": "~4.1.0", "conventional-changelog-cli": "~4.1.0",
"cross-env": "~7.0.3", "cross-env": "~7.0.3",
@ -90,9 +92,9 @@
"lint-staged": "~15.2.11", "lint-staged": "~15.2.11",
"msw": "^2.7.0", "msw": "^2.7.0",
"postcss": "~8.4.49", "postcss": "~8.4.49",
"postcss-html": "~1.7.0", "postcss-html": "~1.8.0",
"postcss-less": "~6.0.0", "postcss-less": "~6.0.0",
"prettier": "~3.3.3", "prettier": "~3.5.3",
"rimraf": "~6.0.1", "rimraf": "~6.0.1",
"stylelint": "~16.10.0", "stylelint": "~16.10.0",
"stylelint-config-property-sort-order-smacss": "^10.0.0", "stylelint-config-property-sort-order-smacss": "^10.0.0",
@ -101,7 +103,7 @@
"stylelint-config-standard": "~36.0.1", "stylelint-config-standard": "~36.0.1",
"stylelint-order": "~6.0.4", "stylelint-order": "~6.0.4",
"stylelint-prettier": "^5.0.3", "stylelint-prettier": "^5.0.3",
"typescript": "~5.6.3", "typescript": "~5.8.2",
"unocss": "^65.5.0", "unocss": "^65.5.0",
"unplugin-vue-components": "~0.27.5", "unplugin-vue-components": "~0.27.5",
"vite": "~6.2.0", "vite": "~6.2.0",
@ -110,8 +112,8 @@
"vite-plugin-mkcert": "^1.17.6", "vite-plugin-mkcert": "^1.17.6",
"vite-plugin-svg-icons": "~2.0.1", "vite-plugin-svg-icons": "~2.0.1",
"vite-plugin-vue-inspector": "^5.3.1", "vite-plugin-vue-inspector": "^5.3.1",
"vue-eslint-parser": "~9.4.3", "vue-eslint-parser": "~10.1.1",
"vue-tsc": "~2.1.10" "vue-tsc": "~2.2.8"
}, },
"keywords": [ "keywords": [
"vue", "vue",

View File

@ -19,12 +19,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from 'vue-router';
import { theme } from 'ant-design-vue'; import { theme } from 'ant-design-vue';
import { useUserStore } from '@/store/modules/user';
import { LockScreen } from '@/components/basic/lockscreen'; import { LockScreen } from '@/components/basic/lockscreen';
import { useRoute } from 'vue-router';
const route = useRoute(); const route = useRoute();
const userStore = useUserStore();
userStore.login();
const { compactAlgorithm } = theme; const { compactAlgorithm } = theme;
</script> </script>

View File

@ -1,21 +1,24 @@
<template> <template>
<!-- <div id="container" /> --> <!-- <div id="container" /> -->
<iframe <!-- <iframe
ref="iframeRef" ref="iframeRef"
width="100%" width="100%"
style="border: none" style="border: none"
height="100%" height="100%"
:src="route.meta?.app?.url" :src="route.meta?.app?.url"
/> /> -->
<!-- <component :is="WujieVue" v-bind="route.meta?.app" /> --> <WujieVue width="100%" height="100%" v-bind="route.meta?.app" />
</template> </template>
<script setup> <script setup>
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import { setupApp, startApp } from 'wujie'; // import { setupApp, startApp } from 'wujie';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import WujieVue from 'wujie-vue3';
const route = useRoute(); const route = useRoute();
console.log(route.meta?.app); // console.log(route.meta?.app);
// onMounted(() => { // onMounted(() => {
// setupApp({ // setupApp({
// el: '#container', // el: '#container',

View File

@ -2,32 +2,37 @@
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import Postmate from 'postmate'; 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 route = useRoute();
const MAX_RETRIES = 3; // const MAX_RETRIES = 3;
const loading = ref(true); const loading = ref(true);
const errorMessage = ref(''); const errorMessage = ref('');
const retryCount = ref(0); // const retryCount = ref(0);
const initPostmate = async () => { const initPostmate = async () => {
loading.value = true; loading.value = true;
errorMessage.value = ''; errorMessage.value = '';
const container = document.getElementById('low-code-adapter'); const container = document.getElementById('low-code-adapter');
console.log('container', container);
if (!container) { if (!container) {
errorMessage.value = '容器元素未找到'; errorMessage.value = '容器元素未找到';
loading.value = false; loading.value = false;
return; return;
} }
const handle = new Postmate({ const connection = new Postmate({
container, container,
url: route.meta?.app?.url, url: route.meta?.app?.url,
name: 'y-code-renderer', name: 'y-code-renderer',
classListArray: ['responsive-iframe'], classListArray: ['responsive-iframe'],
model: { model: {
accessToken: userStore.token,
name: route.meta?.app?.name, name: route.meta?.app?.name,
applicationId: route.meta?.app?.applicationId, applicationId: route.meta?.app?.applicationId,
projectId: route.meta?.app?.projectId, projectId: route.meta?.app?.projectId,
@ -36,23 +41,27 @@
}, },
}); });
handle connection.then((child) => {
.then((instance) => { console.log('Postmate 连接成功', child);
console.log('Postmate连接成功', instance); child.on('some-event', (data) => console.log(data)); // Logs "Hello, World!"
retryCount.value = 0; // child.call('sayHi', {
}) name: route.meta?.app?.name,
.catch((err) => {
retryCount.value++;
errorMessage.value = `连接失败: ${err.message}`;
if (retryCount.value < MAX_RETRIES) {
initPostmate(); //
} else {
errorMessage.value = '已达到最大重试次数,请检查网络连接';
}
})
.finally(() => {
loading.value = false;
}); });
// 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(() => { onMounted(() => {
@ -61,18 +70,7 @@
</script> </script>
<template> <template>
<div class="iframe-container"> <div id="low-code-adapter" />
<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>
</template> </template>
<style> <style>
@ -85,39 +83,8 @@
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.iframe-container {
position: relative;
height: 100%;
}
#low-code-adapter { #low-code-adapter {
width: 100%; width: 100%;
height: 100%; height: 99%;
}
.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;
} }
</style> </style>

View File

@ -2,6 +2,16 @@ export const devMode = 'development';
export const prodMode = 'production'; 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;

View File

@ -1 +1,3 @@
export * from '@sy/low-code-shared/constants'; // export * from '@sy/low-code-shared/constants';
export * from './env';
export * from './low-code';

View File

@ -0,0 +1,2 @@
export const LOW_CODE_APPLICATION_ID = 0;
export const LOW_CODE_PROJECT_ID = 4;

View 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;
};

View File

@ -1,41 +1,41 @@
import axios from 'axios'; 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 { 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 baseApiUrl = import.meta.env.VITE_BASE_API_URL;
// 创建独立实例 // 创建独立实例
const instance = axios.create({ const instance = axios.create({
baseURL: baseApiUrl, // 基础URL直接放在实例配置中 baseURL: baseApiUrl,
}); });
// 请求拦截器改为使用实例
instance.interceptors.request.use( instance.interceptors.request.use(
(config) => { (config) => config,
// 可在此处添加统一请求头等配置 (error) => Promise.reject(error),
return config;
},
(error) => {
return Promise.reject(error);
},
); );
instance.interceptors.request.use(reqInterceptor.fulfilled, reqInterceptor.rejected);
// 响应拦截器改为使用实例 // 响应拦截器
instance.interceptors.response.use( instance.interceptors.response.use(
(response) => { (response) => {
// 如果响应数据中 code 为 -1清空登录状态并跳转到登录页 // 检查是否为401未授权错误
if (response?.data?.code === -1) { if (response.data.code === 401) {
const userStore = useUserStore(); const userStore = useUserStore();
userStore.clearLoginStatus(); // 清空用户信息 console.log('用户未授权或登录已过期,即将跳转...');
router.push('/login'); // 直接使用路由实例 // userStore.logout();
console.error('请求失败:', response.data.msg); // 返回一个永远不会resolve的Promise防止后续代码执行
return new Promise(() => {});
} }
return response; return response;
}, },
(error) => { (error) => Promise.reject(error),
return Promise.reject(error);
},
); );
instance.interceptors.response.use(resInterceptor.fulfilled, resInterceptor.rejected);
// 导出实例 // 导出实例
export default instance; export default instance;

View 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;

View File

@ -9,3 +9,102 @@ export const logout = async () => {
const response = await instance.post('/logout'); const response = await instance.post('/logout');
return response.data; 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;
};

View File

@ -33,10 +33,15 @@
</Menu.Item> --> </Menu.Item> -->
<Menu.Divider /> <Menu.Divider />
<Menu.Item> <Menu.Item>
<div @click.prevent="doLogout"> <div @click.prevent="tianti.logout">
<poweroff-outlined /> {{ $t('layout.header.dropdownItemLoginOut') }} <poweroff-outlined /> {{ $t('layout.header.dropdownItemLoginOut') }}
</div> </div>
</Menu.Item> </Menu.Item>
<Menu.Item v-if="isDevEnv">
<div @click.prevent="tianti.openDev">
{{ $t('layout.header.openDev') }}
</div>
</Menu.Item>
</Menu> </Menu>
</template> </template>
</Dropdown> </Dropdown>
@ -49,6 +54,8 @@
<script lang="tsx" setup> <script lang="tsx" setup>
import { computed, type CSSProperties } from 'vue'; import { computed, type CSSProperties } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import tianti from '@/io/tianti';
import { import {
QuestionCircleOutlined, QuestionCircleOutlined,
MenuFoldOutlined, MenuFoldOutlined,
@ -71,6 +78,8 @@
import { LOGIN_NAME } from '@/router/constant'; import { LOGIN_NAME } from '@/router/constant';
import { useLayoutSettingStore } from '@/store/modules/layoutSetting'; import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
const isDevEnv = import.meta.env.VITE_NODE_ENV === 'development';
defineProps({ defineProps({
collapsed: { collapsed: {
type: Boolean, type: Boolean,

View File

@ -1,20 +1,20 @@
{ {
"footer": { "onlinePreview": "在线预览", "onlineDocument": "在线文档" }, "footer": {
"onlinePreview": "在线预览",
"onlineDocument": "在线文档"
},
"header": { "header": {
"dropdownItemDoc": "文档", "dropdownItemDoc": "文档",
"dropdownItemLoginOut": "退出系统", "dropdownItemLoginOut": "退出系统",
"openDev": "打开开发环境",
"tooltipErrorLog": "错误日志", "tooltipErrorLog": "错误日志",
"tooltipLock": "锁定屏幕", "tooltipLock": "锁定屏幕",
"tooltipNotify": "消息通知", "tooltipNotify": "消息通知",
"tooltipEntryFull": "全屏", "tooltipEntryFull": "全屏",
"tooltipExitFull": "退出全屏", "tooltipExitFull": "退出全屏",
"lockScreenPassword": "锁屏密码", "lockScreenPassword": "锁屏密码",
"lockScreen": "锁定屏幕", "lockScreen": "锁定屏幕",
"lockScreenBtn": "锁定", "lockScreenBtn": "锁定",
"home": "首页" "home": "首页"
}, },
"multipleTab": { "multipleTab": {
@ -38,20 +38,15 @@
"menuTypeMixSidebar": "左侧菜单混合模式", "menuTypeMixSidebar": "左侧菜单混合模式",
"menuTypeMix": "顶部菜单混合模式", "menuTypeMix": "顶部菜单混合模式",
"menuTypeTopMenu": "顶部菜单模式", "menuTypeTopMenu": "顶部菜单模式",
"on": "开", "on": "开",
"off": "关", "off": "关",
"minute": "分钟", "minute": "分钟",
"operatingTitle": "操作成功", "operatingTitle": "操作成功",
"operatingContent": "复制成功,请到 src/settings/projectSetting.ts 中修改配置!", "operatingContent": "复制成功,请到 src/settings/projectSetting.ts 中修改配置!",
"resetSuccess": "重置成功!", "resetSuccess": "重置成功!",
"copyBtn": "拷贝", "copyBtn": "拷贝",
"clearBtn": "清空缓存并返回登录页", "clearBtn": "清空缓存并返回登录页",
"drawerTitle": "项目配置", "drawerTitle": "项目配置",
"darkMode": "主题", "darkMode": "主题",
"navMode": "导航栏模式", "navMode": "导航栏模式",
"interfaceFunction": "界面功能", "interfaceFunction": "界面功能",
@ -59,11 +54,9 @@
"animation": "动画", "animation": "动画",
"splitMenu": "分割菜单", "splitMenu": "分割菜单",
"closeMixSidebarOnChange": "切换页面关闭菜单", "closeMixSidebarOnChange": "切换页面关闭菜单",
"sysTheme": "系统主题", "sysTheme": "系统主题",
"headerTheme": "顶栏主题", "headerTheme": "顶栏主题",
"sidebarTheme": "菜单主题", "sidebarTheme": "菜单主题",
"menuDrag": "侧边菜单拖拽", "menuDrag": "侧边菜单拖拽",
"menuSearch": "菜单搜索", "menuSearch": "菜单搜索",
"menuAccordion": "侧边菜单手风琴模式", "menuAccordion": "侧边菜单手风琴模式",
@ -73,7 +66,6 @@
"menuCollapseButton": "菜单折叠按钮", "menuCollapseButton": "菜单折叠按钮",
"contentMode": "内容区域宽度", "contentMode": "内容区域宽度",
"expandedMenuWidth": "菜单展开宽度", "expandedMenuWidth": "菜单展开宽度",
"breadcrumb": "面包屑", "breadcrumb": "面包屑",
"breadcrumbIcon": "面包屑图标", "breadcrumbIcon": "面包屑图标",
"tabs": "标签页", "tabs": "标签页",
@ -87,22 +79,17 @@
"fullContent": "全屏内容", "fullContent": "全屏内容",
"grayMode": "灰色模式", "grayMode": "灰色模式",
"colorWeak": "色弱模式", "colorWeak": "色弱模式",
"progress": "顶部进度条", "progress": "顶部进度条",
"switchLoading": "切换loading", "switchLoading": "切换loading",
"switchAnimation": "切换动画", "switchAnimation": "切换动画",
"animationType": "动画类型", "animationType": "动画类型",
"autoScreenLock": "自动锁屏", "autoScreenLock": "自动锁屏",
"notAutoScreenLock": "不自动锁屏", "notAutoScreenLock": "不自动锁屏",
"fixedHeader": "固定header", "fixedHeader": "固定header",
"fixedSideBar": "固定Sidebar", "fixedSideBar": "固定Sidebar",
"mixSidebarTrigger": "混合菜单触发方式", "mixSidebarTrigger": "混合菜单触发方式",
"triggerHover": "悬停", "triggerHover": "悬停",
"triggerClick": "点击", "triggerClick": "点击",
"mixSidebarFixed": "固定展开菜单" "mixSidebarFixed": "固定展开菜单"
} }
} }

View File

@ -20,6 +20,7 @@ dayjs.extend(timezone);
const app = createApp(App); const app = createApp(App);
app.use(VueQueryPlugin); app.use(VueQueryPlugin);
function setupPlugins() { function setupPlugins() {
// 安装图标 // 安装图标
setupIcons(); setupIcons();

View 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;

View File

@ -1,4 +1,5 @@
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { Y_CODE_RENDERER_URL } from '@/constants';
// 微前端路由 // 微前端路由
const moduleName = 'application'; const moduleName = 'application';
@ -20,11 +21,11 @@ const routes: Array<RouteRecordRaw> = [
keepAlive: true, keepAlive: true,
icon: 'ant-design:list', icon: 'ant-design:list',
app: { app: {
url: 'https://localhost:10010', url: Y_CODE_RENDERER_URL,
name: 'y-code-platform-application-list', name: 'y-code-platform-application-list',
sync: true, // sync: true,
alive: true, // alive: true,
degrade: true, // degrade: true,
applicationId: 0, applicationId: 0,
projectId: 4, projectId: 4,
fileId: 'b91n1y9yr', fileId: 'b91n1y9yr',

View File

@ -4,4 +4,5 @@ import micro from './micro';
import application from './application'; import application from './application';
import project from './project'; import project from './project';
import staticFile from './static-file'; 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];

View File

@ -1,6 +1,6 @@
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { Y_CODE_DESIGNER_URL, Y_CODE_V1_URL } from '@/constants';
// 微前端路由
const moduleName = 'micro'; const moduleName = 'micro';
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
@ -17,52 +17,36 @@ const routes: Array<RouteRecordRaw> = [
name: `${moduleName}-designer`, name: `${moduleName}-designer`,
meta: { meta: {
title: '低代码编辑器', title: '低代码编辑器',
keepAlive: true,
icon: 'ant-design:edit-outlined', icon: 'ant-design:edit-outlined',
app: { app: {
url: 'https://localhost:10011', url: Y_CODE_DESIGNER_URL,
name: 'y-code-designer', name: 'y-code-designer',
// sync: true, projectId: 4,
// alive: true, sync: true,
// degrade: true, alive: 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,
degrade: true, degrade: true,
}, },
}, },
component: () => import('@/components/micro-container/index.vue'), component: () => import('@/components/renderer-adapter/index.vue'),
}, },
{ {
path: 'y-code-v1', path: 'y-code-v1',
name: `${moduleName}-y-code-v1`, name: `${moduleName}-y-code-v1`,
meta: { meta: {
title: '悦码 1.0', title: '悦码 1.0',
// keepAlive: true, keepAlive: true,
// hideInMenu: true, // hideInMenu: true,
icon: 'ant-design:delete-outlined', icon: 'ant-design:delete-outlined',
app: { app: {
url: 'http://localhost:10012', url: Y_CODE_V1_URL,
name: 'y-code-v1', name: 'y-code-v1',
// sync: true, // sync: true,
// alive: true, // alive: true,
degrade: true, degrade: true,
}, },
}, },
component: () => import('@/components/micro-container/index.vue'), component: () => import('@/components/renderer-adapter/index.vue'),
}, },
], ],
}, },

View File

@ -1,4 +1,6 @@
import type { RouteRecordRaw } from 'vue-router'; 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'; const moduleName = 'project';
@ -20,18 +22,38 @@ const routes: Array<RouteRecordRaw> = [
keepAlive: true, keepAlive: true,
icon: 'ant-design:list', icon: 'ant-design:list',
app: { app: {
url: 'https://localhost:10010', url: Y_CODE_RENDERER_URL,
name: 'y-code-platform-project-list', name: 'y-code-platform-project-list',
// sync: true, // sync: true,
// alive: true, // alive: true,
// degrade: true, // degrade: true,
applicationId: 0, applicationId: LOW_CODE_APPLICATION_ID,
projectId: 4, projectId: LOW_CODE_PROJECT_ID,
fileId: '4g4mz6qi8u', fileId: '4g4mz6qi8u',
}, },
}, },
component: () => import('@/components/renderer-adapter/index.vue'), 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'),
},
], ],
}, },
]; ];

View File

@ -1,4 +1,6 @@
import type { RouteRecordRaw } from 'vue-router'; 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'; const moduleName = 'static-file';
@ -9,7 +11,7 @@ const routes: Array<RouteRecordRaw> = [
name: moduleName, name: moduleName,
meta: { meta: {
title: '静态文件管理', title: '静态文件管理',
icon: 'ant-design:file-outlined', icon: 'ant-design:file',
}, },
children: [ children: [
{ {
@ -18,13 +20,13 @@ const routes: Array<RouteRecordRaw> = [
meta: { meta: {
title: '静态文件列表', title: '静态文件列表',
keepAlive: true, keepAlive: true,
icon: 'ant-design:list', icon: 'ant-design:file',
app: { app: {
url: 'https://localhost:10010', url: Y_CODE_RENDERER_URL,
name: 'y-code-platform-application-list', name: 'y-code-platform-application-list',
sync: true, applicationId: LOW_CODE_APPLICATION_ID,
alive: true, projectId: LOW_CODE_PROJECT_ID,
degrade: true, fileId: '7pfr394d6',
}, },
}, },
component: () => import('@/components/renderer-adapter/index.vue'), component: () => import('@/components/renderer-adapter/index.vue'),

View File

@ -1,4 +1,6 @@
import type { RouteRecordRaw } from 'vue-router'; 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'; const moduleName = 'user';
@ -17,55 +19,20 @@ const routes: Array<RouteRecordRaw> = [
name: `${moduleName}-list`, name: `${moduleName}-list`,
meta: { meta: {
title: '用户列表', title: '用户列表',
icon: 'ant-design:unordered-list-outlined',
keepAlive: true, 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'), component: () => import('@/components/renderer-adapter/index.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'),
}, },
], ],
}, },

View File

@ -1,16 +1,16 @@
import type { RouteRecordRaw } from 'vue-router'; // import type { RouteRecordRaw } from 'vue-router';
import { LOGIN_NAME } from '@/router/constant'; // import { LOGIN_NAME } from '@/router/constant';
/** /**
* layout布局之外的路由 * layout布局之外的路由
*/ */
export const LoginRoute: RouteRecordRaw = { // export const LoginRoute: RouteRecordRaw = {
path: '/login', // path: '/login',
name: LOGIN_NAME, // name: LOGIN_NAME,
component: () => import('@/views/login/index.vue'), // component: () => import('@/views/login/index.vue'),
meta: { // meta: {
title: '登录', // title: '登录',
}, // },
}; // };
export default [LoginRoute]; export default [];

View File

@ -5,8 +5,7 @@ interface KeepAliveState {
list: string[]; list: string[];
} }
export const useKeepAliveStore = defineStore({ export const useKeepAliveStore = defineStore('keep-alive', {
id: 'keep-alive',
state: (): KeepAliveState => ({ state: (): KeepAliveState => ({
list: [], list: [],
}), }),

View File

@ -3,7 +3,8 @@ import { defineStore } from 'pinia';
import { useSSEStore } from './sse'; import { useSSEStore } from './sse';
import { store } from '@/store'; import { store } from '@/store';
import { resetRouter } from '@/router'; import { resetRouter } from '@/router';
import { login, logout } from '@/io'; import tianti from '@/io/tianti';
import { getCurrentUser } from '@/io/user';
export const useUserStore = defineStore( export const useUserStore = defineStore(
'user', 'user',
@ -13,6 +14,10 @@ export const useUserStore = defineStore(
const perms = ref<string[]>([]); const perms = ref<string[]>([]);
const userInfo = ref<Partial<API.UserEntity>>({}); const userInfo = ref<Partial<API.UserEntity>>({});
const setToken = (_token: string) => {
token.value = _token;
};
/** 清空登录态(token、userInfo...) */ /** 清空登录态(token、userInfo...) */
const clearLoginStatus = () => { const clearLoginStatus = () => {
token.value = ''; token.value = '';
@ -23,21 +28,24 @@ export const useUserStore = defineStore(
localStorage.clear(); localStorage.clear();
}); });
}; };
/** 登录成功保存token */
const setToken = (_token: string) => {
token.value = _token;
};
/** 登录 */ /** 登录 */
const login = async (params: any) => { const login = async () => {
const data = await login(params); tianti.checkQuery();
console.log('data', data); const token = localStorage.getItem('y-code-access-token');
// @ts-ignore if (token) {
setToken(data.msg); setToken(token);
setTimeout(() => {
getCurrentUser().then((res) => {
userInfo.value = res.data.data;
console.log('userInfo', userInfo.value);
});
}, 1000);
}
}; };
/** 登出 */ /** 登出 */
const logout = async () => { const logout = async () => {
sseStore.closeEventSource(); sseStore.closeEventSource();
await logout(); await tianti.logout();
clearLoginStatus(); clearLoginStatus();
}; };

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -32,7 +32,7 @@
"strictFunctionTypes": false, "strictFunctionTypes": false,
"noImplicitAny": false, "noImplicitAny": false,
"lib": ["dom", "esnext", "DOM.Iterable"], "lib": ["dom", "esnext", "DOM.Iterable"],
"types": ["node", "vite/client"], "types": ["node", "vite/client", "vue"],
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["src/*"]
} }

View File

@ -14,6 +14,7 @@ declare module 'vue' {
Reflect: Reflect; Reflect: Reflect;
suspenseStatus: '' | 'pending' | 'resolve' | 'fallback'; suspenseStatus: '' | 'pending' | 'resolve' | 'fallback';
} }
export * from '@vue/runtime-core';
} }
declare type Nullable<T> = T | null; declare type Nullable<T> = T | null;

View File

@ -26,7 +26,8 @@ const __APP_INFO__ = {
export default ({ command, mode }: ConfigEnv): UserConfig => { export default ({ command, mode }: ConfigEnv): UserConfig => {
console.log('mode', mode); 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'; const isDev = command === 'serve';
return { return {
@ -46,6 +47,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
server: { server: {
open: true, open: true,
host: true, host: true,
cors: true,
port: Number(env.VITE_PORT),
proxy: { proxy: {
'/api': { '/api': {
target: 'https://custom-chart-pre-api.shiyue.com', target: 'https://custom-chart-pre-api.shiyue.com',

View File

@ -5,9 +5,13 @@ VITE_NODE_ENV = 'development'
VITE_BASE_URL = / VITE_BASE_URL = /
# 前端可见变量(必须以 VITE_ 开头) # 前端可见变量(必须以 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-pre-api.shiyue.com/'
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.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/'

View File

@ -5,3 +5,7 @@ VITE_NODE_ENV = 'production'
VITE_BASE_URL = / VITE_BASE_URL = /
VITE_BASE_API_URL = 'https://custom-chart-api.shiyuegame.com/' 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/'

View File

@ -9,3 +9,7 @@ VITE_PORT = 10010
# base api 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/'

View File

@ -7,7 +7,7 @@ import path from "path";
// @ts-ignore // @ts-ignore
export default defineConfig(({ mode }) => { export default defineConfig(({ mode }) => {
console.log("mode", mode); console.log("mode", mode);
const env = loadEnv(mode, process.cwd(), ["VITE_"]); const env = loadEnv(mode, process.cwd(), ["VITE_", "Y_CODE_"]);
return { return {
server: { server: {

View File

@ -18,13 +18,14 @@
"@sy/low-code-shared": "workspace:*", "@sy/low-code-shared": "workspace:*",
"@sy/web-vitals": "workspace:*", "@sy/web-vitals": "workspace:*",
"@tanstack/vue-query": "^5.66.9", "@tanstack/vue-query": "^5.66.9",
"@vtj/core": "^0.10.9", "@vtj/core": "^0.10.10",
"@vtj/icons": "0.10.9", "@vtj/icons": "0.10.10",
"@vtj/materials": "^0.10.9", "@vtj/materials": "^0.10.10",
"@vtj/pro": "^0.10.9", "@vtj/pro": "^0.10.10",
"@vtj/renderer": "^0.10.9", "@vtj/renderer": "^0.10.10",
"@vtj/ui": "^0.10.9", "@vtj/ui": "^0.10.10",
"@vtj/web": "^0.10.9", "@vtj/utils": "^0.10.10",
"@vtj/web": "^0.10.10",
"axios": "^1.8.1", "axios": "^1.8.1",
"core-js": "^3.40.0", "core-js": "^3.40.0",
"element-plus": "^2.9.4", "element-plus": "^2.9.4",
@ -35,10 +36,10 @@
}, },
"devDependencies": { "devDependencies": {
"@farmfe/cli": "^1.0.4", "@farmfe/cli": "^1.0.4",
"@vtj/cli": "^0.10.2",
"@farmfe/core": "^1.6.6", "@farmfe/core": "^1.6.6",
"@sy/vite-plugin-http2-proxy": "workspace:*", "@sy/vite-plugin-http2-proxy": "workspace:*",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vtj/cli": "^0.10.2",
"vite-plugin-mkcert": "^1.17.6" "vite-plugin-mkcert": "^1.17.6"
} }
} }

View File

@ -6,6 +6,7 @@ import { createProvider } from '@vtj/web'
import { useQuery } from '@tanstack/vue-query' import { useQuery } from '@tanstack/vue-query'
import { LowCodeService } from './service' import { LowCodeService } from './service'
import { getFile } from './io' import { getFile } from './io'
import { request, jsonp } from '@vtj/utils'
// import * as VtjUI from '@vtj/ui' // import * as VtjUI from '@vtj/ui'
// //
@ -13,7 +14,11 @@ const renderer = ref()
const lowCodeService = new LowCodeService() const lowCodeService = new LowCodeService()
// Postmate // Postmate
const handshake = new Postmate.Model({}) const postmate = new Postmate.Model({
sayHi: (data: any) => {
console.log('sayHi',data)
}
})
// //
const model = { const model = {
@ -21,28 +26,33 @@ const model = {
applicationId: -1, applicationId: -1,
projectId: -1, projectId: -1,
fileId: '', fileId: '',
url: '' url: '',
accessToken: ''
} }
// //
const { data: file, isFetching } = useQuery({ const { data: file, isFetching } = useQuery({
queryKey: ['getFile'], queryKey: ['getFile'],
queryFn: async () => { queryFn: async () => {
await handshake.then((parent) => { await postmate.then((parent) => {
// parent.emit('sync-context', 'Hello, World!') parent.emit('some-event', 'y-code-renderer is ready')
Object.assign(model, parent.model) Object.assign(model, parent.model)
localStorage.setItem('y-code-access-token', model.accessToken || '')
// console.log('model', model)
}) })
return getFile(model.fileId).then(() => { return getFile(model.fileId).then(() => {
request.useRequest((req) => {
req.headers.set('Authorization', `Bearer ${model.accessToken}`)
return req
})
const { provider, onReady } = createProvider({ const { provider, onReady } = createProvider({
nodeEnv: import.meta.env.NODE_ENV, nodeEnv: import.meta.env.NODE_ENV,
service: lowCodeService, service: lowCodeService,
project: { id: model.projectId }, project: { id: model.projectId },
// components: { adapter: {
// ...VtjUI, request,
// } jsonp
}
}) })
onReady(async () => { onReady(async () => {
const instance = getCurrentInstance() const instance = getCurrentInstance()

View File

@ -0,0 +1,2 @@
// @ts-ignore
export const currentEnv = __APP_ENV__;

View File

@ -0,0 +1 @@
export * from "./env";

View File

@ -12,7 +12,6 @@ const app = createApp(App);
// 批量注册组件 // 批量注册组件
Object.entries(VtjUI).forEach(([name, component]) => { Object.entries(VtjUI).forEach(([name, component]) => {
console.log("name", name, component);
app.component(name, component); app.component(name, component);
}); });
app app

View File

@ -1,7 +1,7 @@
# .env.development # .env.development
VITE_NODE_ENV = development VITE_NODE_ENV = development
VITE_PORT = 10012 VITE_PORT = 10013
VITE_OA_BASEURL = https://oa-pre.shiyue.com VITE_OA_BASEURL = https://oa-pre.shiyue.com

View File

@ -43,11 +43,11 @@
"eslint-plugin-vue": "^9.32.0", "eslint-plugin-vue": "^9.32.0",
"less": "^4.2.2", "less": "^4.2.2",
"semantic-release": "^24.2.2", "semantic-release": "^24.2.2",
"typescript": "~5.3.3", "typescript": "~5.8.2",
"unplugin-vue-components": "^0.26.0", "unplugin-vue-components": "^0.26.0",
"vite": "^6.2.0", "vite": "^6.2.0",
"vite-plugin-qiankun": "^1.0.15", "vite-plugin-qiankun": "^1.0.15",
"vue-tsc": "^2.2.0", "vue-tsc": "^2.2.8",
"yargs-parser": "^21.1.1" "yargs-parser": "^21.1.1"
}, },
"packageManager": "pnpm@10.4.1" "packageManager": "pnpm@10.4.1"

View File

@ -13,7 +13,7 @@
}, },
"scripts": { "scripts": {
"low-code:help": "node ./scripts/index.mjs", "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", "dev": "turbo run dev",
"build": "turbo run build", "build": "turbo run build",
"preview": "turbo run preview", "preview": "turbo run preview",
@ -38,7 +38,9 @@
"eslint-plugin-prettier": "~5.2.3", "eslint-plugin-prettier": "~5.2.3",
"eslint-plugin-unused-imports": "^4.1.4", "eslint-plugin-unused-imports": "^4.1.4",
"husky": "~9.1.7", "husky": "~9.1.7",
"inquirer": "^12.4.2",
"lint-staged": "~15.2.11", "lint-staged": "~15.2.11",
"ora": "^8.2.0",
"postcss-html": "~1.7.0", "postcss-html": "~1.7.0",
"prettier": "~3.3.3", "prettier": "~3.3.3",
"stylelint": "~16.10.0", "stylelint": "~16.10.0",
@ -48,11 +50,8 @@
"stylelint-config-standard": "~36.0.1", "stylelint-config-standard": "~36.0.1",
"stylelint-order": "~6.0.4", "stylelint-order": "~6.0.4",
"stylelint-prettier": "^5.0.3", "stylelint-prettier": "^5.0.3",
"typescript": "~5.6.3", "typescript": "~5.8.2",
"vue-eslint-parser": "~9.4.3", "vue-eslint-parser": "~10.1.1",
"vue-tsc": "~2.1.10", "vue-tsc": "~2.2.8"
"inquirer": "^12.4.2", }
"ora": "^8.2.0"
},
"dependencies": {}
} }

View File

@ -16,6 +16,6 @@
"clean": "rimraf node_modules" "clean": "rimraf node_modules"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5.7.3" "typescript": "^5.8.2"
} }
} }

1644
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff