Browse Source

chore: 开启微服务

master
wangxiang 2 years ago
parent
commit
6c774ccc1d
  1. 3
      .env
  2. 3
      .env.development
  3. 1
      .eslintignore
  4. 3
      cloud/form-design/package.json
  5. 10
      cloud/form-design/pnpm-lock.yaml
  6. 54
      cloud/form-design/src/main.js
  7. 37
      cloud/form-design/vue.config.js
  8. 23
      package.json
  9. 21
      pnpm-lock.yaml
  10. 6
      src/hooks/setting/index.ts
  11. 25
      src/qiankun/apps.ts
  12. 68
      src/qiankun/index.ts
  13. 39
      src/qiankun/state.ts
  14. 6
      src/utils/env.ts
  15. 78
      src/views/common/workflow/extension/form/helper/WorkflowFormDesign.vue
  16. 4
      types/config.d.ts
  17. 4
      types/global.d.ts

3
.env

@ -15,3 +15,6 @@ VITE_GLOB_CLIENT_SECRET = kicc @@ -15,3 +15,6 @@ VITE_GLOB_CLIENT_SECRET = kicc
# 网关ase密码解密密钥,保持跟后端密钥一致,必须要有否则登录会失败的
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET = changsha-kanglai
# 开启微前端模式
VITE_GLOB_APP_OPEN_QIANKUN=true

3
.env.development

@ -18,3 +18,6 @@ VITE_GLOB_UPLOAD_URL=/upload @@ -18,3 +18,6 @@ VITE_GLOB_UPLOAD_URL=/upload
# 接口地址前缀,有些系统所有接口地址都有前缀,可以在这里统一加,方便切换
VITE_GLOB_API_URL_PREFIX=
#微前端qiankun应用,命名必须以VITE_APP_SUB_开头,form-design为子应用的项目名称,也是子应用的路由父路径
VITE_APP_SUB_form-design = '//localhost:7101'

1
.eslintignore

@ -12,3 +12,4 @@ dist @@ -12,3 +12,4 @@ dist
.local
/bin
Dockerfile
/cloud

3
cloud/form-design/package.json

@ -9,7 +9,8 @@ @@ -9,7 +9,8 @@
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14"
"vue": "^2.6.14",
"vue-router": "3.1.3"
},
"devDependencies": {
"@babel/core": "^7.12.16",

10
cloud/form-design/pnpm-lock.yaml

@ -10,11 +10,13 @@ specifiers: @@ -10,11 +10,13 @@ specifiers:
eslint: ^7.32.0
eslint-plugin-vue: ^8.0.3
vue: ^2.6.14
vue-router: 3.1.3
vue-template-compiler: ^2.6.14
dependencies:
core-js: 3.31.0
vue: 2.7.14
vue-router: 3.1.3_vue@2.7.14
devDependencies:
'@babel/core': 7.22.5
@ -6597,6 +6599,14 @@ packages: @@ -6597,6 +6599,14 @@ packages:
webpack: 5.88.0
dev: true
/vue-router/3.1.3_vue@2.7.14:
resolution: {integrity: sha512-8iSa4mGNXBjyuSZFCCO4fiKfvzqk+mhL0lnKuGcQtO1eoj8nq3CmbEG8FwK5QqoqwDgsjsf1GDuisDX4cdb/aQ==}
peerDependencies:
vue: ^2
dependencies:
vue: 2.7.14
dev: false
/vue-style-loader/4.1.3:
resolution: {integrity: sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==}
dependencies:

54
cloud/form-design/src/main.js

@ -1,8 +1,56 @@ @@ -1,8 +1,56 @@
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
Vue.config.productionTip = false
let router = null;
let instance = null;
new Vue({
render: h => h(App),
}).$mount('#app')
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
mode: 'history',
});
instance = new Vue({
router,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
function storeTest(props) {
props.onGlobalStateChange &&
props.onGlobalStateChange(
(value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
true,
);
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
storeTest(props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}

37
cloud/form-design/vue.config.js

@ -1,4 +1,39 @@ @@ -1,4 +1,39 @@
const { defineConfig } = require('@vue/cli-service')
const path = require('path');
const { name } = require('./package');
function resolve(dir) {
return path.join(__dirname, dir);
}
const port = 7101; // dev port
module.exports = defineConfig({
transpileDependencies: true
outputDir: 'dist',
assetsDir: 'static',
filenameHashing: true,
transpileDependencies: true,
devServer: {
// host: '0.0.0.0',
hot: true,
port,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
// 自定义webpack配置
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
},
},
output: {
// 把子应用打包成 umd 库格式
library: `${name}-[name]`,
libraryTarget: 'umd'
},
},
})

23
package.json

@ -25,28 +25,30 @@ @@ -25,28 +25,30 @@
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@iconify/iconify": "^2.1.30",
"@vueuse/core": "^9.1.1",
"@vueuse/shared": "^9.1.1",
"@zxcvbn-ts/core": "^2.0.1",
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0",
"@iconify/iconify": "^2.1.30",
"@vue/runtime-core": "^3.2.33",
"@vue/shared": "^3.2.33",
"@vueuse/core": "^9.1.1",
"@vueuse/shared": "^9.1.1",
"@zxcvbn-ts/core": "^2.0.1",
"ant-design-vue": "^3.2.12",
"axios": "^0.26.1",
"cropperjs": "^1.5.12",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.1",
"echarts": "^5.3.2",
"intro.js": "^5.1.0",
"event-source-polyfill": "^1.0.31",
"exceljs": "^4.3.0",
"intro.js": "^5.1.0",
"js-base64": "^3.6.1",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "^2.0.13",
"print-js": "^1.6.0",
"qiankun": "^2.10.9",
"qrcode": "^1.5.0",
"qs": "^6.10.3",
"resize-observer-polyfill": "^1.5.1",
@ -57,7 +59,6 @@ @@ -57,7 +59,6 @@
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.14",
"vue-types": "^4.1.1",
"exceljs": "^4.3.0",
"vxe-table": "^4.3.9",
"vxe-table-plugin-antd": "^3.0.5",
"vxe-table-plugin-export-xlsx": "^3.0.4",
@ -70,11 +71,11 @@ @@ -70,11 +71,11 @@
"@types/crypto-js": "^4.1.1",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.2.1",
"@types/intro.js": "^3.0.2",
"@types/lodash-es": "^4.17.6",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0",
"@types/qs": "^6.9.7",
"@types/intro.js": "^3.0.2",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
@ -82,7 +83,6 @@ @@ -82,7 +83,6 @@
"@vitejs/plugin-vue": "^2.3.3",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/compiler-sfc": "^3.2.33",
"picocolors": "^1.0.0",
"autoprefixer": "^10.4.4",
"conventional-changelog-cli": "^2.2.2",
"cross-env": "^7.0.3",
@ -94,6 +94,7 @@ @@ -94,6 +94,7 @@
"fs-extra": "^10.1.0",
"inquirer": "^8.2.2",
"less": "^4.1.2",
"picocolors": "^1.0.0",
"postcss": "^8.4.12",
"rimraf": "^3.0.2",
"rollup": "^2.70.2",
@ -103,6 +104,8 @@ @@ -103,6 +104,8 @@
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1",
"vite-plugin-purge-icons": "^0.8.2",
"vite-plugin-pwa": "^0.12.3",
"vite-plugin-style-import": "^2.0.0",
@ -110,9 +113,7 @@ @@ -110,9 +113,7 @@
"vite-plugin-theme": "^0.8.6",
"vite-plugin-windicss": "^1.8.7",
"vue-eslint-parser": "^8.3.0",
"vue-tsc": "^1.0.9",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1"
"vue-tsc": "^1.0.9"
},
"resolutions": {
"bin-wrapper": "npm:bin-wrapper-china",

21
pnpm-lock.yaml

@ -59,6 +59,7 @@ specifiers: @@ -59,6 +59,7 @@ specifiers:
pinia: ^2.0.13
postcss: ^8.4.12
print-js: ^1.6.0
qiankun: ^2.10.9
qrcode: ^1.5.0
qs: ^6.10.3
resize-observer-polyfill: ^1.5.1
@ -118,6 +119,7 @@ dependencies: @@ -118,6 +119,7 @@ dependencies:
path-to-regexp: 6.2.1
pinia: 2.0.33_hmuptsblhheur2tugfgucj7gc4
print-js: 1.6.0
qiankun: 2.10.9
qrcode: 1.5.1
qs: 6.11.1
resize-observer-polyfill: 1.5.1
@ -5638,6 +5640,12 @@ packages: @@ -5638,6 +5640,12 @@ packages:
resolve-from: 4.0.0
dev: true
/import-html-entry/1.14.6:
resolution: {integrity: sha512-5MQkbwIr8n/bXOoE05M5/Nm0lnHO46vnb3D6svSvtVwpDqwhd/X14zjLcU31QWZ6gL8rUXNzj6vKHx4yOUL6gQ==}
dependencies:
'@babel/runtime': 7.21.0
dev: false
/import-lazy/4.0.0:
resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
engines: {node: '>=8'}
@ -7543,6 +7551,15 @@ packages: @@ -7543,6 +7551,15 @@ packages:
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
dev: true
/qiankun/2.10.9:
resolution: {integrity: sha512-+DOdKnmFMoMfIWZaoLaBVoHAPlEWg529ZtIBnoNLUTJq4CreHIhXjnqc0mlxCCg4axZKtcORDPMAk4kPG6IH3A==}
dependencies:
'@babel/runtime': 7.21.0
import-html-entry: 1.14.6
lodash: 4.17.21
single-spa: 5.9.5
dev: false
/qrcode/1.5.1:
resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==}
engines: {node: '>=10.13.0'}
@ -8058,6 +8075,10 @@ packages: @@ -8058,6 +8075,10 @@ packages:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/single-spa/5.9.5:
resolution: {integrity: sha512-9SQdmsyz4HSP+3gs6PJzhkaMEg+6zTlu9oxIghnwUX3eq+ajq4ft5egl0iyR55LAmO/UwvU8NgIWs/ZyQMa6dw==}
dev: false
/slash/3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}

6
src/hooks/setting/index.ts

@ -18,7 +18,8 @@ export const useGlobSetting = (): Readonly<GlobConfig> => { @@ -18,7 +18,8 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
VITE_GLOB_UPLOAD_URL,
VITE_GLOB_CLIENT_ID,
VITE_GLOB_CLIENT_SECRET,
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET,
VITE_GLOB_APP_OPEN_QIANKUN,
} = getAppEnvConfig();
if (!/[a-zA-Z\_]*/.test(VITE_GLOB_APP_SHORT_NAME)) {
@ -34,7 +35,8 @@ export const useGlobSetting = (): Readonly<GlobConfig> => { @@ -34,7 +35,8 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
uploadUrl: VITE_GLOB_UPLOAD_URL,
clientId: VITE_GLOB_CLIENT_ID,
clientSecret: VITE_GLOB_CLIENT_SECRET,
gatewayAseEncodeSecret: VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET
gatewayAseEncodeSecret: VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET,
openQianKun: VITE_GLOB_APP_OPEN_QIANKUN
};
return glob as Readonly<GlobConfig>;
};

25
src/qiankun/apps.ts

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
/**
*apps
* @name: -
* @entry: . -
* @container: -
* @activeRule: -
*/
import type { RegistrableApp } from 'qiankun';
import { ComponentOptions } from '@vue/runtime-core';
//子应用列表
const _apps: RegistrableApp<object>[] = [];
for (const key in import.meta.env) {
if (key.includes('VITE_APP_SUB_')) {
const name = key.split('VITE_APP_SUB_')[1];
const obj = {
name,
entry: import.meta.env[key],
container: '#content',
activeRule: name,
};
_apps.push(obj);
}
}
export const apps = _apps;

68
src/qiankun/index.ts

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
/**
* qiankun配置
*/
import { registerMicroApps, setDefaultMountApp, start, runAfterFirstMounted, addGlobalUncaughtErrorHandler } from 'qiankun';
import { apps } from './apps';
import { getProps, initGlState } from './state';
/**
* apps
*/
function filterApps() {
apps.forEach((item) => {
//主应用需要传递给微应用的数据。
item.props = getProps();
//微应用触发的路由规则
item.activeRule = genActiveRule('/' + item.activeRule);
});
return apps;
}
/**
*
* @param {*} routerPrefix
*/
function genActiveRule(routerPrefix) {
return (location) => location.pathname.startsWith(routerPrefix);
}
/**
*
*/
function registerApps() {
const _apps = filterApps();
registerMicroApps(_apps, {
beforeLoad: [
(loadApp) => Promise.resolve(()=>{
console.log('before load', loadApp);
}),
],
beforeMount: [
(mountApp) => Promise.resolve(()=>{
console.log('before mount', mountApp);
}),
],
afterMount: [
(mountApp) => Promise.resolve(()=>{
console.log('before mount', mountApp);
}),
],
afterUnmount: [
(unloadApp) => Promise.resolve(()=>{
console.log('after unload', unloadApp);
}),
],
});
// 设置默认子应用,与 genActiveRule中的参数保持一致
// setDefaultMountApp();
// 第一个微应用 mount 后需要调用的方法,比如开启一些监控或者埋点脚本。
runAfterFirstMounted(() => console.log('开启监控'));
// 添加全局的未捕获异常处理器。
addGlobalUncaughtErrorHandler((event) => console.log(event));
// 定义全局状态
initGlState();
//启动qiankun
start({});
}
export default registerApps;

39
src/qiankun/state.ts

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
/**
*
*/
import { initGlobalState, RegistrableApp } from 'qiankun';
import { store } from '/@/store';
import { router } from '/@/router';
import { getAccessToken } from '/@/utils/auth';
//定义传入子应用的数据
export function getProps(){
return {
data: {
publicPath: '/',
token: getAccessToken(),
store,
router,
},
};
}
/**
* ,使 props
* @param state 穿
*/
export function initGlState(info = { userName: 'admin' }) {
// 初始化state
const actions = initGlobalState(info);
// 设置新的值
actions.setGlobalState(info);
// 注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。
actions.onGlobalStateChange((newState, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.info('newState', newState);
console.info('prev', prev);
for (const key in newState) {
console.info('onGlobalStateChange', key);
}
});
}

6
src/utils/env.ts

@ -36,7 +36,8 @@ export function getAppEnvConfig() { @@ -36,7 +36,8 @@ export function getAppEnvConfig() {
VITE_GLOB_UPLOAD_URL,
VITE_GLOB_CLIENT_ID,
VITE_GLOB_CLIENT_SECRET,
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET,
VITE_GLOB_APP_OPEN_QIANKUN,
} = ENV;
if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) {
@ -53,7 +54,8 @@ export function getAppEnvConfig() { @@ -53,7 +54,8 @@ export function getAppEnvConfig() {
VITE_GLOB_UPLOAD_URL,
VITE_GLOB_CLIENT_ID,
VITE_GLOB_CLIENT_SECRET,
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET,
VITE_GLOB_APP_OPEN_QIANKUN,
};
}

78
src/views/common/workflow/extension/form/helper/WorkflowFormDesign.vue

@ -4,67 +4,52 @@ @@ -4,67 +4,52 @@
@register="registerModal"
@ok="handleSubmit"
>
<loquat-form-design ref="loquat-form-design"
style="height:calc(100vh - 133px)"
:toolbar="['clear', 'preview']"
:options="state.options"
:custom-fields="state.customFields"
/>
<div id="vue" class="app-view-box"/>
</BasicModal>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { onMounted, reactive, nextTick } from 'vue';
import { BasicModal, ModalProps, useModalInner } from '/@/components/Modal';
import { useGlobSetting } from '/@/hooks/setting';
import registerApps from '/@/qiankun';
import { loadMicroApp } from 'qiankun';
/*onMounted(() => {
/!* //注册openQianKun
if (openQianKun) {
if (!window.qiankunStarted) {
window.qiankunStarted = true;
registerApps();
}
}*!/
nextTick(() => );
loadMicroApp(
{ name: 'form-design', entry: '//localhost:7101', container: '#form-design' },
{ sandbox: { experimentalStyleIsolation: true } },
);
});*/
interface TableState {
tag: string;
options: Recordable;
customFields: Recordable[];
}
const state = reactive<TableState>({
tag: '',
options: {},
customFields: [{
title: '自定义字段',
list: [
{
title: '分割线',
type: 'custom',
component: 'el-divider',
icon: 'iconfont icon-divider',
label: '',
propExclude: true,
labelWidth: 0,
params: {
html: '<h3 style="color:red">分割线标题</h3>',
contentPosition: 'left'
}
},
{
title: '警告',
type: 'custom',
component: 'el-alert',
icon: 'el-icon-warning',
label: '',
propExclude: true,
labelWidth: 0,
params: {
title: '警告警告警告警告',
type: 'success'
},
events: {
close () {
console.log('alert关闭事件');
}
}
}
]
}],
});
const globSetting = useGlobSetting();
const openQianKun = globSetting.openQianKun;
const emit = defineEmits(['success', 'register']);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data: BoxPayload = { _tag: '' }) => {
loadMicroApp(
{ name: 'vue', entry: '//localhost:7101', container: '#vue' },
{ sandbox: { experimentalStyleIsolation: true } }
);
state.tag = data._tag;
const id = data.record?.id;
const props: Partial<ModalProps> = { confirmLoading: false };
@ -79,6 +64,7 @@ @@ -79,6 +64,7 @@
setModalProps(props);
});
/** 处理弹出框提交 */
async function handleSubmit() {
try {

4
types/config.d.ts vendored

@ -152,6 +152,8 @@ export interface GlobConfig { @@ -152,6 +152,8 @@ export interface GlobConfig {
clientSecret: string;
// 网关ase密码解密密钥,保持跟后端密钥一致,必须要有否则登录会失败的
gatewayAseEncodeSecret: string;
// 开启微服务
openQianKun?: boolean;
}
export interface GlobEnvConfig {
@ -171,4 +173,6 @@ export interface GlobEnvConfig { @@ -171,4 +173,6 @@ export interface GlobEnvConfig {
VITE_GLOB_CLIENT_SECRET: string;
// 网关ase密码解密密钥,保持跟后端密钥一致,必须要有否则登录会失败的
VITE_GLOB_GATEWAY_ASE_ENCODE_SECRET: string;
// 开启微服务
VITE_GLOB_APP_OPEN_QIANKUN: boolean;
}

4
types/global.d.ts vendored

@ -29,6 +29,10 @@ declare global { @@ -29,6 +29,10 @@ declare global {
declare type IntervalHandle = ReturnType<typeof setInterval>;
interface Window {
qiankunStarted: boolean
}
declare interface ChangeEvent extends Event {
target: HTMLInputElement;
}

Loading…
Cancel
Save