签入版本
This commit is contained in:
@@ -2,10 +2,10 @@
|
||||
VITE_PORT = 8001
|
||||
|
||||
# spa-title
|
||||
VITE_GLOB_APP_TITLE = Django+ElementPlus版
|
||||
VITE_GLOB_APP_TITLE = Flask+ElementPlus版
|
||||
|
||||
# spa shortname
|
||||
VITE_GLOB_APP_SHORT_NAME = Django+ElementPlus版
|
||||
VITE_GLOB_APP_SHORT_NAME = Flask+ElementPlus版
|
||||
|
||||
# 生产环境 开启mock
|
||||
VITE_GLOB_PROD_MOCK = false
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ VITE_USE_MOCK = false
|
||||
VITE_DROP_CONSOLE = true
|
||||
|
||||
# 跨域代理,可以配置多个,请注意不要换行
|
||||
VITE_PROXY=[["/api","http://127.0.0.1:8021/"]]
|
||||
VITE_PROXY=[["/api","http://127.0.0.1:8021/api/v1"]]
|
||||
|
||||
# API 接口地址
|
||||
VITE_GLOB_API_URL =
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
### Django+ElementPlus版
|
||||
### Flask+ElementPlus版
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* The name of the configuration file entered in the production environment
|
||||
*/
|
||||
export const GLOB_CONFIG_FILE_NAME = 'app.config.js';
|
||||
|
||||
export const OUTPUT_DIR = 'dist';
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Get the configuration file variable name
|
||||
* @param env
|
||||
*/
|
||||
export const getConfigFileName = (env: Record<string, any>) => {
|
||||
const safe = (env.VITE_GLOB_APP_SHORT_NAME || '__APP')
|
||||
.replace(/[^\w]/g, '_') // 非字母数字→_
|
||||
.replace(/_{2,}/g, '_') // 连续 _ 变单个
|
||||
.replace(/^_|_$/g, '') // 去掉首尾 _
|
||||
.toUpperCase();
|
||||
return `__PRODUCTION_${safe}__CONF__`;
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Generate additional configuration files when used for packaging. The file can be configured with some global variables, so that it can be changed directly externally without repackaging
|
||||
*/
|
||||
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
|
||||
import fs, { writeFileSync } from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { getRootPath, getEnvConfig } from '../utils';
|
||||
import { getConfigFileName } from '../getConfigFileName';
|
||||
|
||||
import pkg from '../../package.json';
|
||||
|
||||
function createConfig(
|
||||
{
|
||||
configName,
|
||||
config,
|
||||
configFileName = GLOB_CONFIG_FILE_NAME,
|
||||
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} }
|
||||
) {
|
||||
try {
|
||||
const windowConf = `window.${configName}`;
|
||||
// Ensure that the variable will not be modified
|
||||
const configStr = `${windowConf}=${JSON.stringify(config)};
|
||||
Object.freeze(${windowConf});
|
||||
Object.defineProperty(window, "${configName}", {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
});
|
||||
`.replace(/\s/g, '');
|
||||
fs.mkdirp(getRootPath(OUTPUT_DIR));
|
||||
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
|
||||
|
||||
console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
|
||||
console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n');
|
||||
} catch (error) {
|
||||
console.log(chalk.red('configuration file configuration file failed to package:\n' + error));
|
||||
}
|
||||
}
|
||||
|
||||
export function runBuildConfig() {
|
||||
const config = getEnvConfig();
|
||||
const configFileName = getConfigFileName(config);
|
||||
createConfig({ config, configName: configFileName });
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// #!/usr/bin/env node
|
||||
|
||||
import { runBuildConfig } from './buildConf';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import pkg from '../../package.json';
|
||||
|
||||
export const runBuild = async () => {
|
||||
try {
|
||||
const argvList = process.argv.splice(2);
|
||||
|
||||
// Generate configuration file
|
||||
if (!argvList.includes('disabled-config')) {
|
||||
await runBuildConfig();
|
||||
}
|
||||
|
||||
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
|
||||
} catch (error) {
|
||||
console.log(chalk.red('vite build error:\n' + error));
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
runBuild();
|
||||
@@ -0,0 +1,71 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
export function isDevFn(mode: string): boolean {
|
||||
return mode === 'development';
|
||||
}
|
||||
|
||||
export function isProdFn(mode: string): boolean {
|
||||
return mode === 'production';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to generate package preview
|
||||
*/
|
||||
export function isReportMode(): boolean {
|
||||
return process.env.REPORT === 'true';
|
||||
}
|
||||
|
||||
// Read all environment variable configuration files to process.env
|
||||
export function wrapperEnv(envConf: Recordable): ViteEnv {
|
||||
const ret: any = {};
|
||||
|
||||
for (const envName of Object.keys(envConf)) {
|
||||
let realName = envConf[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
|
||||
if (envName === 'VITE_PORT') {
|
||||
realName = Number(realName);
|
||||
}
|
||||
if (envName === 'VITE_PROXY') {
|
||||
try {
|
||||
realName = JSON.parse(realName);
|
||||
} catch (error) {}
|
||||
}
|
||||
ret[envName] = realName;
|
||||
process.env[envName] = realName;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the environment variables starting with the specified prefix
|
||||
* @param match prefix
|
||||
* @param confFiles ext
|
||||
*/
|
||||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.production']) {
|
||||
let envConfig = {};
|
||||
confFiles.forEach((item) => {
|
||||
try {
|
||||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
|
||||
envConfig = { ...envConfig, ...env };
|
||||
} catch (error) {}
|
||||
});
|
||||
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
});
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user root directory
|
||||
* @param dir file path
|
||||
*/
|
||||
export function getRootPath(...dir: string[]) {
|
||||
return path.resolve(process.cwd(), ...dir);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
|
||||
* https://github.com/anncwb/vite-plugin-compression
|
||||
*/
|
||||
import type { Plugin } from 'vite';
|
||||
|
||||
import compressPlugin from 'vite-plugin-compression';
|
||||
|
||||
export function configCompressPlugin(
|
||||
compress: 'gzip' | 'brotli' | 'none',
|
||||
deleteOriginFile = false
|
||||
): Plugin | Plugin[] {
|
||||
const compressList = compress.split(',');
|
||||
|
||||
const plugins: Plugin[] = [];
|
||||
|
||||
if (compressList.includes('gzip')) {
|
||||
plugins.push(
|
||||
compressPlugin({
|
||||
ext: '.gz',
|
||||
deleteOriginFile,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (compressList.includes('brotli')) {
|
||||
plugins.push(
|
||||
compressPlugin({
|
||||
ext: '.br',
|
||||
algorithm: 'brotliCompress',
|
||||
deleteOriginFile,
|
||||
})
|
||||
);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Plugin to minimize and use ejs template syntax in index.html.
|
||||
* https://github.com/anncwb/vite-plugin-html
|
||||
*/
|
||||
import type { PluginOption } from 'vite';
|
||||
import { createHtmlPlugin } from 'vite-plugin-html';
|
||||
import pkg from '../../../package.json';
|
||||
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
|
||||
|
||||
export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
|
||||
const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
|
||||
|
||||
const path = VITE_PUBLIC_PATH.endsWith('/') ? VITE_PUBLIC_PATH : `${VITE_PUBLIC_PATH}/`;
|
||||
|
||||
const getAppConfigSrc = () => {
|
||||
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`;
|
||||
};
|
||||
|
||||
const htmlPlugin: PluginOption[] = createHtmlPlugin({
|
||||
minify: isBuild,
|
||||
inject: {
|
||||
// Inject data into ejs template
|
||||
data: {
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
},
|
||||
// Embed the generated app.config.js file
|
||||
tags: isBuild
|
||||
? [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: getAppConfigSrc(),
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
},
|
||||
});
|
||||
return htmlPlugin;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { PluginOption } from 'vite';
|
||||
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
|
||||
// 自动按需导入,根据自身情况选择
|
||||
import AutoImport from 'unplugin-auto-import/vite';
|
||||
// import Components from 'unplugin-vue-components/vite';
|
||||
// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
|
||||
// import Components from 'unplugin-vue-components/vite';
|
||||
// import ElementPlus from 'unplugin-element-plus/vite';
|
||||
|
||||
import { configHtmlPlugin } from './html';
|
||||
import { configMockPlugin } from './mock';
|
||||
import { configCompressPlugin } from './compress';
|
||||
import { configVisualizerPlugin } from './visualizer';
|
||||
|
||||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, prodMock) {
|
||||
const { VITE_USE_MOCK, VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv;
|
||||
|
||||
const vitePlugins: (PluginOption | PluginOption[])[] = [
|
||||
// have to
|
||||
vue(),
|
||||
// have to
|
||||
vueJsx(),
|
||||
VueSetupExtend(),
|
||||
// ElementPlus({
|
||||
// // 引入的样式的类型,可以是css、sass、less等,
|
||||
// importStyle: 'sass',
|
||||
// useSource: true,
|
||||
// }),
|
||||
// 按需引入element且自动创建组件声明
|
||||
AutoImport({
|
||||
imports: ['vue', 'vue-router', 'pinia'], // 自动导入的依赖库数组
|
||||
dts: './auto-imports.d.ts', // 自动导入类型定义文件路径
|
||||
}),
|
||||
// Components({
|
||||
// resolvers: [ElementPlusResolver()],
|
||||
// }),
|
||||
];
|
||||
|
||||
// vite-plugin-html
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-mock
|
||||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild, prodMock));
|
||||
|
||||
// rollup-plugin-visualizer
|
||||
vitePlugins.push(configVisualizerPlugin());
|
||||
|
||||
if (isBuild) {
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(
|
||||
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
|
||||
);
|
||||
}
|
||||
|
||||
return vitePlugins;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Mock plugin for development and production.
|
||||
* https://github.com/anncwb/vite-plugin-mock
|
||||
*/
|
||||
import { viteMockServe } from 'vite-plugin-mock';
|
||||
|
||||
export function configMockPlugin(isBuild: boolean, prodMock: boolean) {
|
||||
return viteMockServe({
|
||||
ignore: /^\_/,
|
||||
mockPath: 'mock',
|
||||
localEnabled: !isBuild,
|
||||
prodEnabled: isBuild && prodMock,
|
||||
injectCode: `
|
||||
import { setupProdMockServer } from '../mock/_createProductionServer';
|
||||
|
||||
setupProdMockServer();
|
||||
`,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { PluginOption } from 'vite';
|
||||
import visualizer from 'rollup-plugin-visualizer';
|
||||
import { isReportMode } from '../../utils';
|
||||
|
||||
export function configVisualizerPlugin() {
|
||||
if (isReportMode()) {
|
||||
return visualizer({
|
||||
filename: './node_modules/.cache/visualizer/stats.html',
|
||||
open: true,
|
||||
gzipSize: true,
|
||||
brotliSize: true,
|
||||
}) as PluginOption;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Used to parse the .env.development proxy configuration
|
||||
*/
|
||||
import type { ProxyOptions } from 'vite';
|
||||
|
||||
type ProxyItem = [string, string];
|
||||
|
||||
type ProxyList = ProxyItem[];
|
||||
|
||||
type ProxyTargetList = Record<string, ProxyOptions & { rewrite: (path: string) => string }>;
|
||||
|
||||
const httpsRE = /^https:\/\//;
|
||||
|
||||
/**
|
||||
* Generate proxy
|
||||
* @param list
|
||||
*/
|
||||
export function createProxy(list: ProxyList = []) {
|
||||
const ret: ProxyTargetList = {};
|
||||
for (const [prefix, target] of list) {
|
||||
const isHttps = httpsRE.test(target);
|
||||
|
||||
// https://github.com/http-party/node-http-proxy#options
|
||||
ret[prefix] = {
|
||||
target: target,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
|
||||
// https is require secure=false
|
||||
...(isHttps ? { secure: false } : {}),
|
||||
};
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "djangoadmin",
|
||||
"version": "3.0.0",
|
||||
"description": "Django+ElementPlus版",
|
||||
"description": "Flask+ElementPlus版",
|
||||
"license": "Apache-2.0",
|
||||
"author": {
|
||||
"name": "Django+ElementPlus版",
|
||||
"name": "Flask+ElementPlus版",
|
||||
"email": "djangoadmin@126.com",
|
||||
"url": "https://www.djangoadmin.cn"
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@@ -61,3 +61,13 @@ export function getTemplateByCode(code: any) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 发送消息
|
||||
*/
|
||||
export function sendMsg(data) {
|
||||
return http.request({
|
||||
url: '/websocket/sendMsg',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export function jobBatchDelete(data: any) {
|
||||
export function getJobRunOnce(id) {
|
||||
return http.request({
|
||||
url: '/job/runOnce/' + id,
|
||||
method: 'get',
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export function setJobStatus(data: any) {
|
||||
export function getJobPause(id) {
|
||||
return http.request({
|
||||
url: '/job/pause/' + id,
|
||||
method: 'get',
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ export function getJobPause(id) {
|
||||
export function getJobResume(id) {
|
||||
return http.request({
|
||||
url: '/job/resume/' + id,
|
||||
method: 'get',
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -1,7 +1,7 @@
|
||||
import { http } from '@/utils/http/axios';
|
||||
|
||||
/**
|
||||
* @description: 案例分页列表
|
||||
* @description: 案例演示分页列表
|
||||
*/
|
||||
export function getExamplePage(params?) {
|
||||
return http.request({
|
||||
@@ -12,7 +12,7 @@ export function getExamplePage(params?) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部案例列表
|
||||
* 获取全部案例演示列表
|
||||
* @param params 参数
|
||||
* @returns 返回结果
|
||||
*/
|
||||
@@ -25,8 +25,8 @@ export function getExampleList(params?) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 根据ID获取案例详情
|
||||
* @param id 案例ID
|
||||
* @description: 根据ID获取案例演示详情
|
||||
* @param id 案例演示ID
|
||||
*/
|
||||
export function getExampleDetail(id) {
|
||||
return http.request({
|
||||
@@ -36,8 +36,8 @@ export function getExampleDetail(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 添加案例
|
||||
* @param data 案例数据
|
||||
* @description: 添加案例演示
|
||||
* @param data 案例演示数据
|
||||
*/
|
||||
export function exampleAdd(data: any) {
|
||||
return http.request({
|
||||
@@ -48,8 +48,8 @@ export function exampleAdd(data: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 更新案例
|
||||
* @param data 案例数据
|
||||
* @description: 更新案例演示
|
||||
* @param data 案例演示数据
|
||||
*/
|
||||
export function exampleUpdate(data: any) {
|
||||
return http.request({
|
||||
@@ -60,8 +60,8 @@ export function exampleUpdate(data: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 删除案例
|
||||
* @param id 案例ID
|
||||
* @description: 删除案例演示
|
||||
* @param id 案例演示ID
|
||||
*/
|
||||
export function exampleDelete(id) {
|
||||
return http.request({
|
||||
@@ -71,8 +71,8 @@ export function exampleDelete(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 批量删除案例
|
||||
* @param data 案例ID数组
|
||||
* @description: 批量删除案例演示
|
||||
* @param data 案例演示ID数组
|
||||
*/
|
||||
export function exampleBatchDelete(data: any) {
|
||||
return http.request({
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 381 KiB |
@@ -70,9 +70,9 @@
|
||||
},
|
||||
});
|
||||
const upload = ref<UploadInstance>();
|
||||
const uploadHeaders = reactive({
|
||||
const uploadHeaders = computed(() => ({
|
||||
authorization: 'Bearer ' + useUserStore().getToken,
|
||||
});
|
||||
}));
|
||||
const emit = defineEmits(['success', 'update:visible']);
|
||||
|
||||
const dialogClose = () => {
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<div class="page-footer">
|
||||
<div class="page-footer-link">
|
||||
<a href="https://www.djangoadmin.cn" target="_blank"> 官网 </a>
|
||||
<a href="http://docs.django.elevue.djangoadmin.cn" target="_blank"> 文档 </a>
|
||||
<a href="http://docs.flask.elevue.djangoadmin.cn" target="_blank"> 文档 </a>
|
||||
<a href="https://www.djangoadmin.cn/goods/detail/2" target="_blank"> 授权 </a>
|
||||
</div>
|
||||
<div class="copyright">Copyright © 2026 珊瑚云研发团队</div>
|
||||
<div class="copyright">Copyright © 2026 小蚂蚁云研发团队</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'password',
|
||||
field: 'oldPassword',
|
||||
component: 'Input',
|
||||
type: 'password',
|
||||
label: '旧密码',
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
>
|
||||
<div v-if="navMode === 'horizontal'" class="logo">
|
||||
<img alt="" src="~@/assets/images/logo.png" />
|
||||
<h2 v-show="!collapsed" class="title">Django+ElementPlus版</h2>
|
||||
<h2 v-show="!collapsed" class="title">Flask+ElementPlus版</h2>
|
||||
</div>
|
||||
</div>
|
||||
<!--左侧菜单-->
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<h2
|
||||
v-show="!isCollapsed || navMode === 'horizontal' || (navMode === 'horizontal-mix' && mixMenu)"
|
||||
class="mt-0 title"
|
||||
>Django+ElementPlus版</h2
|
||||
>Flask+ElementPlus版</h2
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+19
-2
@@ -74,11 +74,14 @@
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<check-token />
|
||||
<!-- 全局WebSocket通讯组件 -->
|
||||
<!-- <global-websocket :uri="'/api/websocket/' + userInfo.id" @rollback="rollback" />
|
||||
<check-token /> -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, computed, onMounted, watch, provide, defineAsyncComponent } from 'vue';
|
||||
import { ref, unref, computed, onMounted, watch, provide, h, defineAsyncComponent } from 'vue';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import { Logo } from './components/Logo';
|
||||
import { TabsView } from './components/TagsView';
|
||||
import { MainView } from './components/Main';
|
||||
@@ -98,6 +101,7 @@
|
||||
/**
|
||||
* 定义参数
|
||||
*/
|
||||
const GlobalWebsocket = defineAsyncComponent(() => import('@/components/Websocket/index.vue'));
|
||||
const CheckToken = defineAsyncComponent(() => import('@/components/CheckToken/index.vue'));
|
||||
const { getDarkTheme } = useDesignSetting();
|
||||
const {
|
||||
@@ -231,6 +235,19 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 消息通知回调
|
||||
* @param msg 消息
|
||||
*/
|
||||
const rollback = (msg) => {
|
||||
// ElNotification({
|
||||
// type: 'info',
|
||||
// title: '通知',
|
||||
// message: h('div', msg),
|
||||
// duration: 5000,
|
||||
// });
|
||||
};
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,7 @@ export const LoginRoute: RouteRecordRaw = {
|
||||
name: 'Login',
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
meta: {
|
||||
title: '登录 - Django+ElementPlus前后端分离版本',
|
||||
title: '登录 - Flask+ElementPlus前后端分离版本',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -282,11 +282,11 @@
|
||||
{
|
||||
icon: BarChartOutlined,
|
||||
size: '32',
|
||||
title: '租户管理',
|
||||
title: '角色管理',
|
||||
color: '#69c0ff',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
router.push({ path: '/system/tenant' });
|
||||
router.push({ path: '/system/role' });
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -326,11 +326,11 @@
|
||||
{
|
||||
icon: MailOutlined,
|
||||
size: '32',
|
||||
title: '消息管理',
|
||||
title: '文件管理',
|
||||
color: '#5cdbd3',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
router.push({ path: '/data/message' });
|
||||
router.push({ path: '/file/fileTemplate' });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="account-container">
|
||||
<div class="account-wrap-login">
|
||||
<div class="login-pic">
|
||||
<h1 class="login-title">Django+ElementPlus前后端分离版本</h1>
|
||||
<h1 class="login-title">Flask+ElementPlus前后端分离版本</h1>
|
||||
<h4 class="login-subtitle">数字化赋能,助力企业发展,全方位提供数据中台解决方案!</h4>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
* 定义操作栏
|
||||
*/
|
||||
const actionColumn = reactive({
|
||||
width: 350,
|
||||
width: 370,
|
||||
label: '操作',
|
||||
prop: 'action',
|
||||
fixed: 'right',
|
||||
@@ -109,6 +109,7 @@
|
||||
actions: [
|
||||
{
|
||||
label: '启动',
|
||||
icon: 'Clock',
|
||||
type: 'success',
|
||||
onClick: handelChangeStatus.bind(null, record),
|
||||
auth: ['sys:job:resume'],
|
||||
@@ -118,6 +119,7 @@
|
||||
},
|
||||
{
|
||||
label: '暂停',
|
||||
icon: 'Clock',
|
||||
type: 'warning',
|
||||
onClick: handelChangeStatus.bind(null, record),
|
||||
auth: ['sys:job:pause'],
|
||||
@@ -258,6 +260,7 @@
|
||||
const handelChangeStatus = async (record) => {
|
||||
await confirm(`确定要${record.row.status == 1 ? '暂停' : '启动'}`);
|
||||
record.row.status == 1 ? await getJobPause(record.row.id) : await getJobResume(record.row.id);
|
||||
message('执行成功');
|
||||
reloadTable('noRefresh');
|
||||
};
|
||||
const handelRunOnce = async (record) => {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
type="danger"
|
||||
@click="handleDelete()"
|
||||
:disabled="!selectionData.length"
|
||||
v-perm="['sys:operLog:batchDelete']"
|
||||
v-perm="['sys:operationLog:batchDelete']"
|
||||
>
|
||||
<template #icon>
|
||||
<el-icon class="el-input__icon">
|
||||
@@ -79,14 +79,14 @@
|
||||
icon: 'View',
|
||||
type: 'warning',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
auth: ['sys:operLog:detail'],
|
||||
auth: ['sys:operationLog:detail'],
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
icon: 'Delete',
|
||||
type: 'danger',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
auth: ['sys:operLog:delete'],
|
||||
auth: ['sys:operationLog:delete'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -84,6 +84,8 @@
|
||||
dialogTitle="导入用户"
|
||||
@success="reloadTable()"
|
||||
/>
|
||||
<!-- 发送WebSocket消息 -->
|
||||
<sendMsgDialog v-if="sendMsgVisible" v-model:visible="sendMsgVisible" :receiveId="receiveId" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
@@ -108,12 +110,15 @@
|
||||
* 定义参数
|
||||
*/
|
||||
const userId = ref(0);
|
||||
const receiveId = ref('');
|
||||
const tableRef = ref();
|
||||
const editVisible = ref(false);
|
||||
const sendMsgVisible = ref(false);
|
||||
const importVisible = ref(false);
|
||||
const selectionData = ref([]);
|
||||
const exportLoading = ref(false);
|
||||
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
|
||||
const sendMsgDialog = defineAsyncComponent(() => import('./sendMsg.vue'));
|
||||
const fileUpload = defineAsyncComponent(() => import('@/components/importFile/index.vue'));
|
||||
|
||||
/**
|
||||
@@ -273,6 +278,20 @@
|
||||
message('导出成功');
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* 此处写的是Socket消息发送案例,实际业务研发时根据实际需求自行接入模板消息
|
||||
*/
|
||||
const sendMessage = async () => {
|
||||
if (selectionData.value.length == 0) {
|
||||
message('请选择数据', 'error');
|
||||
return;
|
||||
}
|
||||
let ids = [];
|
||||
ids = selectionData.value.map(({ id }) => id);
|
||||
receiveId.value = ids.join();
|
||||
sendMsgVisible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -66,8 +66,8 @@ export const columns = [
|
||||
// 状态标签渲染
|
||||
render(record) {
|
||||
const statusMap = {
|
||||
1: { text: '正常', type: 'success' },
|
||||
2: { text: '禁用', type: 'danger' },
|
||||
1: { text: '在用', type: 'success' },
|
||||
2: { text: '停用', type: 'danger' },
|
||||
};
|
||||
const status = statusMap[record.row.status];
|
||||
return h(
|
||||
@@ -82,7 +82,7 @@ export const columns = [
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '排序',
|
||||
label: '案例排序',
|
||||
prop: 'sort',
|
||||
minWidth: 100,
|
||||
// 普通文本渲染
|
||||
@@ -97,4 +97,4 @@ export const columns = [
|
||||
prop: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="props.visible"
|
||||
title="案例详情"
|
||||
title="案例演示详情"
|
||||
width="750"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="dialogClose"
|
||||
@@ -26,7 +26,7 @@
|
||||
<el-descriptions-item label="案例状态:" label-class-name="des-width">
|
||||
<span>{{ getChoiceLabel('status', formData.status) }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="排序:" label-class-name="des-width">
|
||||
<el-descriptions-item label="案例排序:" label-class-name="des-width">
|
||||
{{ formData.sort || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@@ -85,8 +85,8 @@
|
||||
4: '类型4',
|
||||
},
|
||||
status: {
|
||||
1: '正常',
|
||||
2: '禁用',
|
||||
1: '在用',
|
||||
2: '停用',
|
||||
},
|
||||
};
|
||||
return choiceMap[fieldName]?.[value] || value || '-';
|
||||
@@ -112,7 +112,7 @@
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取案例详情失败', error);
|
||||
console.error('获取案例演示详情失败', error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -180,4 +180,4 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="props.visible"
|
||||
:title="props.id ? '编辑案例' : '新增案例'"
|
||||
:title="props.id ? '编辑案例演示' : '新增案例演示'"
|
||||
width="500"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="dialogClose"
|
||||
@@ -20,6 +20,7 @@
|
||||
<el-form-item
|
||||
label="案例图片"
|
||||
prop="avatar"
|
||||
:rules="{ required: true, message: '请上传案例图片', trigger: 'change' }"
|
||||
>
|
||||
<UploadImg
|
||||
@changeFileName="(name) => (formData.avatarImgName = name)"
|
||||
@@ -35,7 +36,6 @@
|
||||
<el-form-item
|
||||
label="案例类型"
|
||||
prop="type"
|
||||
:rules="{ required: true, message: '请选择案例类型:1-类型1 2-类型2 3-类型3 4-类型4', trigger: 'change' }"
|
||||
>
|
||||
<el-select
|
||||
v-model="formData.type"
|
||||
@@ -51,22 +51,20 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 案例状态:1-正常 2-禁用(单选) -->
|
||||
<!-- 案例状态:1-在用 2-停用(单选) -->
|
||||
<el-form-item
|
||||
label="案例状态"
|
||||
prop="status"
|
||||
:rules="{ required: true, message: '请选择案例状态:1-正常 2-禁用', trigger: 'change' }"
|
||||
>
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :value="1">正常</el-radio>
|
||||
<el-radio :value="2">禁用</el-radio>
|
||||
<el-radio :value="1">在用</el-radio>
|
||||
<el-radio :value="2">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 排序(数字输入) -->
|
||||
<!-- 案例排序(数字输入) -->
|
||||
<el-form-item
|
||||
label="排序"
|
||||
label="案例排序"
|
||||
prop="sort"
|
||||
:rules="{ required: true, message: '请输入排序', trigger: 'blur' }"
|
||||
>
|
||||
<el-input-number v-model="formData.sort" :min="0" :max="99999" />
|
||||
</el-form-item>
|
||||
@@ -194,7 +192,7 @@
|
||||
}
|
||||
// 设置富文本编辑器内容
|
||||
} catch (error) {
|
||||
console.error('获取案例详情失败', error);
|
||||
console.error('获取案例演示详情失败', error);
|
||||
message('获取数据失败', 'error');
|
||||
}
|
||||
};
|
||||
@@ -232,4 +230,4 @@
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<PlusOutlined />
|
||||
</el-icon>
|
||||
</template>
|
||||
添加案例
|
||||
添加案例演示
|
||||
</el-button>
|
||||
|
||||
<!-- 批量删除按钮 -->
|
||||
@@ -229,7 +229,7 @@
|
||||
}
|
||||
}
|
||||
// 确认删除
|
||||
await confirm('确定要删除选中的案例吗?');
|
||||
await confirm('确定要删除选中的案例演示吗?');
|
||||
// 执行删除操作
|
||||
record ? await exampleDelete(record.row.id) : await exampleBatchDelete(ids);
|
||||
message('删除成功');
|
||||
@@ -243,6 +243,7 @@
|
||||
function onSelectionChange(value) {
|
||||
selectionData.value = value;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -50,14 +50,14 @@ export const schemas: FormSchema[] = [
|
||||
clearable: true,
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
label: '在用',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
label: '停用',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user