icssoa 1 rok temu
rodzic
commit
42b406e028

+ 15 - 13
build/cool/eps/index.ts

@@ -65,19 +65,21 @@ async function getData(temps?: Eps.Entity[]) {
 
 // 创建 json 文件
 function createJson() {
-	const d = list.map((e) => {
-		return {
-			prefix: e.prefix,
-			name: e.name || "",
-			api: e.api.map((e) => {
-				return {
-					name: e.name,
-					method: e.method,
-					path: e.path
-				};
-			})
-		};
-	});
+	const d = list
+		.filter((e) => !e.isLocal) // 过滤本地的 service 数据
+		.map((e) => {
+			return {
+				prefix: e.prefix,
+				name: e.name || "",
+				api: e.api.map((e) => {
+					return {
+						name: e.name,
+						method: e.method,
+						path: e.path
+					};
+				})
+			};
+		});
 
 	createWriteStream(join(DistPath, "eps.json"), {
 		flags: "w"

+ 1 - 0
build/cool/types/index.d.ts

@@ -28,5 +28,6 @@ export namespace Eps {
 		module: string;
 		name: string;
 		prefix: string;
+		[key: string]: any;
 	}
 }

+ 3 - 4
index.html

@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
 	<head>
 		<meta charset="utf-8" />
@@ -22,7 +22,7 @@
 				margin: 0;
 				padding: 0;
 				font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
-					"Microsoft YaHei", Arial, sans-serif;
+					"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
 			}
 
 			.preload__wrap {
@@ -93,8 +93,7 @@
 				border: 7px solid currentColor;
 				border-bottom-color: #2f3447 !important;
 				position: relative;
-				animation:
-					r 1s infinite cubic-bezier(0.17, 0.67, 0.83, 0.67),
+				animation: r 1s infinite cubic-bezier(0.17, 0.67, 0.83, 0.67),
 					bc 2s infinite ease-in;
 				transform: rotate(0deg);
 			}

+ 2 - 1
src/config/proxy.ts

@@ -1,6 +1,7 @@
 export const proxy = {
 	"/dev/": {
-		target: "http://127.0.0.1:8001",
+		// target: "http://127.0.0.1:8001",
+		target: "https://test-admin.cool-js.cloud",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace(/^\/dev/, "")
 	},

+ 74 - 24
src/cool/bootstrap/eps.ts

@@ -1,30 +1,85 @@
 import { merge } from "lodash-es";
-import { service } from "../service";
+import { BaseService, service } from "../service";
 import { Module } from "../types";
 import { path2Obj } from "../utils";
 import { config, isDev } from "/@/config";
+import { eps } from "virtual:eps";
 
 export function createEps(modules: Module[]) {
-	// 本地模块的数据
-	const s = path2Obj(
-		modules.reduce((a, b) => {
-			return a.concat(...((b.services as any[]) || []));
-		}, [])
-	);
+	// 更新数据
+	function update() {
+		// 设置 request 方法
+		function set(d: any) {
+			if (d.namespace) {
+				const a = new BaseService(d.namespace);
 
-	// 合并数据
-	merge(service, s);
+				for (const i in d) {
+					const { path, method = "get" } = d[i];
 
-	// 开发环境下,生成本地 service 的类型文件
+					if (path) {
+						a.request = a.request;
+
+						a[i] = function (data?: any) {
+							return this.request({
+								url: path,
+								method,
+								[method.toLocaleLowerCase() == "post" ? "data" : "params"]: data
+							});
+						};
+					}
+				}
+
+				for (const i in a) {
+					d[i] = a[i];
+				}
+			} else {
+				for (const i in d) {
+					set(d[i]);
+				}
+			}
+		}
+
+		// 遍历每一个方法
+		set(eps.service);
+
+		// 合并[eps]
+		merge(service, eps.service);
+
+		// 合并[local]
+		merge(
+			service,
+			path2Obj(
+				modules.reduce((a, b) => {
+					return a.concat(...((b.services as any[]) || []));
+				}, [])
+			)
+		);
+
+		// 提示
+		if (isDev) {
+			console.log("[eps] update", service);
+		}
+	}
+
+	update();
+
+	// 监听 vite 触发事件
+	if (import.meta.hot) {
+		import.meta.hot.on("eps-update", () => {
+			update();
+		});
+	}
+
+	// 开发环境下,生成本地 service 的类型描述文件
 	if (isDev && config.test.eps) {
 		const list: any[] = [];
 
 		// 模拟 eps 数据
-		function deep(s: any) {
-			if (s.namespace) {
+		modules.forEach((m) => {
+			m.services?.forEach((s) => {
 				const api = Array.from(
 					new Set([
-						...Object.getOwnPropertyNames(s.constructor.prototype),
+						...Object.getOwnPropertyNames(s.value.constructor.prototype),
 						"page",
 						"list",
 						"info",
@@ -42,18 +97,13 @@ export function createEps(modules: Module[]) {
 
 				list.push({
 					api,
-					module: s.namespace.split("/")[0],
-					name: s.constructor.name + "Entity",
-					prefix: `/admin/${s.namespace}`
+					module: m.name,
+					name: s.value.constructor.name + "Entity",
+					prefix: `/admin/${s.path}`,
+					isLocal: true
 				});
-			} else {
-				for (const i in s) {
-					deep(s[i]);
-				}
-			}
-		}
-
-		deep(s);
+			});
+		});
 
 		// 生成文件
 		service.request({

+ 3 - 58
src/cool/service/index.ts

@@ -1,64 +1,9 @@
 import { BaseService } from "./base";
-import { hmr } from "../hook";
-import { eps } from "virtual:eps";
-import { merge } from "lodash-es";
 
 // service 数据集合
-export const service: Eps.Service = hmr.getData("service", {
+export const service: Eps.Service = {
+	// @ts-ignore
 	request: new BaseService().request
-});
-
-// 同步 service 数据
-function update() {
-	function deep(d: any) {
-		if (d.namespace) {
-			const a = new BaseService(d.namespace);
-
-			for (const i in d) {
-				const { path, method = "get" } = d[i];
-
-				if (path) {
-					a.request = a.request;
-
-					a[i] = function (data?: any) {
-						return this.request({
-							url: path,
-							method,
-							[method.toLocaleLowerCase() == "post" ? "data" : "params"]: data
-						});
-					};
-				}
-			}
-
-			for (const i in a) {
-				d[i] = a[i];
-			}
-		} else {
-			for (const i in d) {
-				deep(d[i]);
-			}
-		}
-	}
-
-	// 遍历
-	deep(eps.service);
-
-	// 合并
-	merge(service, eps.service);
-
-	// 缓存
-	hmr.setData("service", service);
-
-	// tips
-	console.log("[eps] update");
-}
-
-update();
-
-if (import.meta.hot) {
-	import.meta.hot.on("eps-update", () => {
-		update();
-	});
-}
+};
 
 export * from "./base";

+ 1 - 1
src/modules/base/components/select/index.tsx

@@ -1,5 +1,5 @@
 import { useCrud } from "@cool-vue/crud";
-import { isObject, isString } from "lodash-es";
+import { isString } from "lodash-es";
 import { computed, defineComponent, isRef, PropType, Ref, ref, watch } from "vue";
 import { parsePx } from "/@/cool/utils";
 

+ 0 - 7
src/modules/base/static/css/index.scss

@@ -1,10 +1,3 @@
-* {
-	padding: 0;
-	margin: 0;
-	font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
-		"微软雅黑", Arial, sans-serif;
-}
-
 *::-webkit-scrollbar {
 	width: 10px;
 	height: 10px;

+ 2 - 1
src/modules/demo/components/form-btn.vue

@@ -104,7 +104,8 @@ function open() {
 			labelPosition: "top"
 		},
 		dialog: {
-			height: "500px"
+			height: "500px",
+			width: "1000px"
 		},
 		items: [
 			{

+ 216 - 0
src/modules/demo/components/select-user.vue

@@ -0,0 +1,216 @@
+<template>
+	<div class="select-user__inner">
+		<div class="btns">
+			<el-button type="success" @click="open">添加</el-button>
+			<el-button type="danger" :disabled="list.length == 0" @click="remove">移除</el-button>
+		</div>
+
+		<cl-table :data="list" :ref="setRefs('table')" :auto-height="false" />
+	</div>
+
+	<cl-dialog v-model="visible" width="1200px" title="选择用户">
+		<cl-crud ref="Crud">
+			<cl-row>
+				<!-- 刷新按钮 -->
+				<cl-refresh-btn />
+
+				<cl-filter label="状态">
+					<cl-select :options="options.status" prop="status" :width="120" />
+				</cl-filter>
+
+				<cl-flex1 />
+				<!-- 关键字搜索 -->
+				<cl-search-key placeholder="搜索昵称" />
+			</cl-row>
+
+			<cl-row>
+				<!-- 数据表格 -->
+				<cl-table ref="Table" :auto-height="false" />
+			</cl-row>
+
+			<cl-row>
+				<span>已选 {{ Table?.selection.length }} 人</span>
+				<cl-flex1 />
+				<!-- 分页控件 -->
+				<cl-pagination />
+			</cl-row>
+		</cl-crud>
+
+		<template #footer>
+			<el-button @click="close">取消</el-button>
+			<el-button type="success" @click="select">选择</el-button>
+		</template>
+	</cl-dialog>
+</template>
+
+<script lang="ts" setup name="select-user">
+import { useCrud, useForm, useTable } from "@cool-vue/crud";
+import { useCool } from "/@/cool";
+import { nextTick, reactive, ref, watch } from "vue";
+import { cloneDeep } from "lodash";
+
+const props = defineProps({
+	modelValue: {
+		type: Array,
+		default: () => []
+	},
+	isDisabled: Boolean,
+	prop: String,
+	scope: null,
+	disabled: Boolean
+});
+
+const emit = defineEmits(["update:modelValue"]);
+
+const { service, refs, setRefs } = useCool();
+
+// 上级表单
+const Form = useForm();
+
+// 选项
+const options = reactive({
+	status: [
+		{
+			label: "启用",
+			value: 1,
+			type: "success"
+		},
+		{
+			label: "禁用",
+			value: 0,
+			type: "danger"
+		}
+	]
+});
+
+// cl-table
+const Table = useTable({
+	columns: [
+		{
+			type: "selection",
+			width: 60,
+			reserveSelection: true
+		},
+		{
+			prop: "headImg",
+			label: "头像",
+			component: {
+				name: "cl-avatar"
+			}
+		},
+		{
+			prop: "username",
+			label: "手机号",
+			minWidth: 150
+		},
+		{
+			prop: "name",
+			label: "姓名",
+			minWidth: 150
+		},
+		{
+			prop: "departmentName",
+			label: "部门名称",
+			minWidth: 150
+		},
+		{
+			label: "状态",
+			prop: "status",
+			minWidth: 100,
+			dict: options.status
+		},
+		{
+			label: "创建时间",
+			prop: "createTime",
+			sortable: "desc",
+			minWidth: 160
+		}
+	]
+});
+
+// cl-crud
+const Crud = useCrud({
+	service: service.base.sys.user,
+	async onRefresh(params, { next }) {
+		await next(params);
+
+		// 数据反选
+		list.value.forEach((e) => {
+			const d = Table.value?.data.find((a) => a.id == e.id);
+
+			if (d) {
+				Table.value?.toggleRowSelection(d, true);
+			}
+		});
+	}
+});
+
+// 刷新
+async function refresh(params?: any) {
+	return Crud.value?.refresh(params);
+}
+
+// 弹窗是否可见
+const visible = ref(false);
+
+// 已选列表
+const list = ref<Eps.BaseSysUserEntity[]>([]);
+
+// 打开选择弹窗
+function open() {
+	visible.value = true;
+
+	nextTick(() => {
+		refresh({
+			size: 10
+		});
+	});
+}
+
+// 关闭选择弹窗
+function close() {
+	visible.value = false;
+}
+
+// 选择
+function select() {
+	list.value = cloneDeep(Table.value?.selection || []);
+	close();
+}
+
+// 移除
+function remove() {
+	const ids = (refs.table.selection as any[]).map((e) => e.id);
+
+	list.value = list.value.filter((e) => {
+		// 清空选择状态
+		refs.table.toggleRowSelection(e, false);
+
+		// 移除已选的
+		return !ids.find((id) => id == e.id);
+	});
+}
+
+// 监听已选列表,返回 ids
+watch(
+	list,
+	(arr) => {
+		emit(
+			"update:modelValue",
+			arr.map((e) => e.id)
+		);
+		Form.value?.validateField(props.prop);
+	},
+	{
+		deep: true
+	}
+);
+</script>
+
+<style lang="scss" scoped>
+.select-user__inner {
+	.btns {
+		margin-bottom: 10px;
+	}
+}
+</style>

+ 20 - 3
src/modules/demo/views/crud.vue

@@ -45,7 +45,7 @@
 					},
 					{ label: '手机号', value: 'phone' }
 				]"
-				:width="200"
+				:width="250"
 			/>
 
 			<!-- 高级搜索按钮 -->
@@ -88,7 +88,11 @@
 		</cl-row>
 
 		<!-- 新增、编辑 -->
-		<cl-upsert ref="Upsert" />
+		<cl-upsert ref="Upsert">
+			<template #slot-userIds="{ scope }">
+				<select-user v-model="scope.userIds" />
+			</template>
+		</cl-upsert>
 
 		<!-- 高级搜索 -->
 		<cl-adv-search ref="AdvSearch" />
@@ -102,6 +106,7 @@ import { reactive } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import { useCool } from "/@/cool";
 import FormBtn from "../components/form-btn.vue";
+import SelectUser from "../components/select-user.vue";
 
 // 基础
 const { service, refs, setRefs } = useCool();
@@ -156,6 +161,11 @@ function refresh(params?: any) {
 
 // 新增、编辑
 const Upsert = useUpsert({
+	dialog: {
+		height: "600px", // 固定高
+		width: "1000px" // 固定宽
+	},
+
 	items: [
 		// 分组
 		{
@@ -232,7 +242,6 @@ const Upsert = useUpsert({
 				}
 			]
 		},
-
 		{
 			label: "省市区",
 			prop: "pca",
@@ -241,6 +250,14 @@ const Upsert = useUpsert({
 				name: "cl-distpicker"
 			}
 		},
+		{
+			label: "选择用户",
+			prop: "userIds",
+			group: "base",
+			component: {
+				name: "slot-userIds"
+			}
+		},
 
 		{
 			label: "工作",