神仙都没用 1 年間 前
コミット
1ff3964f28

ファイルの差分が大きいため隠しています
+ 2228 - 223
build/cool/eps.d.ts


ファイルの差分が大きいため隠しています
+ 0 - 0
build/cool/eps.json


+ 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: "http://192.168.0.112:9009",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace(/^\/dev/, "")
 	},

+ 1 - 1
src/modules/helper/config.ts

@@ -10,7 +10,7 @@ export default (): ModuleConfig => {
 			order: 1,
 			component: import("./components/auto-menu/btn.vue")
 		},
-		views: [
+		pages: [
 			{
 				path: "/helper/ai-code",
 				meta: {

+ 1 - 0
src/modules/helper/static/svg/editor-code.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1718961548891" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2699" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M330.6 311.2c-16.7-16.7-43.7-16.7-60.3 0L67.6 513.8l202.9 199.3c8.3 8.1 19.1 12.2 29.9 12.2 11 0 22.1-4.2 30.4-12.8 16.5-16.8 16.3-43.8-0.5-60.4l-141.5-139 141.8-141.8c16.7-16.5 16.7-43.5 0-60.1zM757.5 311.4c-16.5-16.8-43.5-17.1-60.3-0.5-16.8 16.5-17 43.5-0.5 60.3l139.5 142-139.3 139.3c-16.7 16.7-16.7 43.7 0 60.3 8.3 8.3 19.2 12.5 30.2 12.5s21.8-4.2 30.2-12.5l199.1-199-198.9-202.4zM564.8 256.8c-23.1-4.5-45.6 10.4-50.2 33.5L429.3 717c-4.6 23.1 10.4 45.6 33.5 50.2 2.8 0.6 5.6 0.8 8.4 0.8 19.9 0 37.8-14 41.8-34.3L598.3 307c4.6-23.1-10.4-45.6-33.5-50.2z" p-id="2700"></path></svg>

+ 483 - 228
src/modules/helper/views/ai-code.vue

@@ -1,174 +1,123 @@
 <template>
 	<el-scrollbar :ref="setRefs('scrollbar')">
 		<div class="ai-code">
-			<div class="container">
-				<div class="head">
-					<text2 model-value="Cool Ai 极速编码" />
-				</div>
-
-				<div class="form">
-					<el-form :disabled="temp.disabled" size="large">
-						<div class="label required">CRUD</div>
-
-						<el-row :gutter="10">
-							<el-col :lg="6" :xs="24" :sm="12">
-								<cl-select
-									class="module"
-									placeholder="请选择模块"
-									v-model="form.module"
-									:options="module.dirs"
-									label-key="name"
-									value-key="name"
-									allow-create
-								/>
-							</el-col>
-
-							<el-col :lg="6" :xs="24" :sm="12">
-								<el-input
-									class="name"
-									v-model="form.name"
-									placeholder="实体名称,如:收货地址"
-								/>
-							</el-col>
-
-							<el-col :lg="12" :xs="24" :sm="24">
-								<el-input
-									class="columns"
-									v-model="form.columns"
-									placeholder="请填写字段,如:姓名、年龄、状态"
-								/>
-							</el-col>
-						</el-row>
-
-						<div class="label">其他你想做的事?</div>
-
-						<el-input
-							type="textarea"
-							v-model="form.other"
-							:rows="5"
-							placeholder="如:分页查询时姓名、手机号字段设置成可模糊搜索"
-						/>
-					</el-form>
-				</div>
-
-				<div class="btns">
-					<el-button
-						round
-						size="large"
-						type="primary"
-						:icon="Promotion"
-						:disabled="temp.disabled"
-						:loading="temp.disabled"
-						@click="next"
-					>
-						{{ temp.disabled ? "思考中" : codes.entity.length ? "重新生成" : "下一步" }}
-					</el-button>
-				</div>
+			<div class="bg">
+				<div class="a"></div>
+				<div class="b"></div>
+			</div>
 
-				<div class="tips">如遇见 “代码缺失”、“请求超时”,请尝试「刷新」吧</div>
+			<div class="panels" :class="[`is-${step.value}`]">
+				<div class="panel-free">
+					<div class="head">
+						<p class="title">Cool Ai 极速编码</p>
+						<p class="tag">让软件开发<span>再</span>快一点</p>
+						<p class="desc">
+							{{ desc.text }}
+						</p>
+					</div>
 
-				<!-- 代码 -->
-				<div class="codes">
-					<div class="item is-entity" v-show="codes.entity">
-						<div class="label">
-							<div class="name">
-								<span>Entity(实体类)</span>
-								<el-icon class="is-loading" v-show="temp.coding == 'entity'">
-									<loading />
-								</el-icon>
+					<div class="editor">
+						<div class="topbar">
+							<div class="dots">
+								<span></span>
+								<span></span>
+								<span></span>
 							</div>
+						</div>
 
-							<template v-if="!temp.disabled">
-								<el-button round size="small" @click="copyCode('entity')"
-									>Copy</el-button
-								>
-								<el-button
-									round
-									type="success"
-									size="small"
-									:loading="!codes.vue"
-									@click="createVue()"
+						<div class="content">
+							<div class="form">
+								<div
+									class="form-item"
+									v-for="(item, index) in form.list"
+									:key="index"
 								>
-									生成Vue代码
-								</el-button>
-							</template>
+									<p class="label">{{ item.label }}</p>
+
+									<el-input resize="none" :placeholder="item.desc">
+										<template #prefix>
+											<el-icon>
+												<arrow-right />
+											</el-icon>
+										</template>
+									</el-input>
+								</div>
+							</div>
 						</div>
+					</div>
 
-						<cl-editor
-							name="cl-editor-monaco"
-							:ref="setRefs('codeEntity')"
-							:options="editor.options"
-							height="auto"
-							autofocus
-							autosize
-							language="typescript"
-							v-model="codes.entity"
-						/>
+					<div class="btns">
+						<el-button
+							size="large"
+							color="#41d1ff"
+							:icon="Promotion"
+							:disabled="temp.disabled"
+							:loading="temp.disabled"
+							@click="next"
+						>
+							{{
+								temp.disabled
+									? "思考中"
+									: codes.entity.length
+									  ? "重新生成"
+									  : "下一步"
+							}}
+						</el-button>
 					</div>
 
-					<div class="item is-controller" v-show="codes.controller">
-						<div class="label">
-							<div class="name">
-								<span>Controller(控制层)</span>
-								<el-icon class="is-loading" v-show="temp.coding == 'controller'">
-									<loading />
-								</el-icon>
+					<div class="tips">如遇见 “代码缺失”、“请求超时”,请尝试「刷新」吧</div>
+				</div>
+
+				<div class="panel-code">
+					<div class="editor">
+						<div class="topbar">
+							<div class="dots">
+								<span @click="step.prev"></span>
+								<span></span>
+								<span></span>
 							</div>
 
-							<template v-if="!temp.disabled">
-								<el-button round size="small" @click="copyCode('controller')"
-									>Copy</el-button
-								>
-							</template>
+							<div class="print">
+								<el-icon class="is-loading">
+									<refresh />
+								</el-icon>
+								<span>生成 vue 代码中</span>
+							</div>
 						</div>
 
-						<cl-editor
-							name="cl-editor-monaco"
-							:ref="setRefs('codeController')"
-							:options="editor.options"
-							height="auto"
-							autosize
-							language="typescript"
-							v-model="codes.controller"
-						/>
-					</div>
+						<div class="content">
+							<div class="tabs">
+								<div class="item">Entity 实体数据</div>
+								<div class="item active">Service 服务层</div>
+								<div class="item">Controll 控制器</div>
+								<div class="item">Vue 前端页面</div>
+
+								<div class="op">
+									<el-icon>
+										<download />
+									</el-icon>
+								</div>
+							</div>
 
-					<div class="item is-vue" v-show="codes.vue">
-						<div class="label">
-							<div class="name">
-								<span>Vue(页面)</span>
-								<el-icon class="is-loading" v-show="temp.coding == 'vue'">
-									<loading />
-								</el-icon>
+							<div class="code">
+								<cl-editor-monaco
+									height="100%"
+									:border="false"
+									:options="{
+										theme: 'ai-code--dark'
+									}"
+								/>
 							</div>
 
-							<template v-if="!temp.disabled">
-								<el-button round size="small" @click="copyCode('vue')"
-									>Copy</el-button
-								>
-							</template>
+							<!-- <div class="op">
+								<el-button :icon="CloseBold" @click="reset"> 取消 </el-button>
+								<el-button color="#41d1ff" @click="createFile">
+									创建文件
+								</el-button>
+							</div> -->
 						</div>
-
-						<cl-editor
-							name="cl-editor-monaco"
-							:ref="setRefs('codeVue')"
-							:options="editor.options"
-							height="auto"
-							autosize
-							language="html"
-							v-model="codes.vue"
-						/>
 					</div>
 				</div>
-
-				<div class="op" v-show="!temp.disabled && codes.entity.length">
-					<el-button :icon="Close" round size="large" @click="reset"> 取消 </el-button>
-					<el-button :icon="Check" round size="large" type="success" @click="createFile">
-						创建文件
-					</el-button>
-				</div>
-
-				<div class="bottom"></div>
 			</div>
 
 			<!-- 创建菜单 -->
@@ -179,8 +128,8 @@
 
 <script lang="tsx" setup name="helper-ai-code">
 import { onMounted, reactive, watch } from "vue";
-import { module, useCool, storage } from "/@/cool";
-import { Promotion, Loading, Close, Check } from "@element-plus/icons-vue";
+import { useCool, storage } from "/@/cool";
+import { Promotion, Refresh, Download, ArrowRight } from "@element-plus/icons-vue";
 import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
 import { debounce, isEmpty } from "lodash-es";
 import { useClipboard } from "@vueuse/core";
@@ -188,7 +137,7 @@ import { useMenu, useAi } from "../hooks";
 import { isDev } from "/@/config";
 import { useForm } from "@cool-vue/crud";
 import type { CodeType } from "../types";
-import Text2 from "../components/text.vue";
+import * as monaco from "monaco-editor";
 
 const { service, refs, setRefs } = useCool();
 const { copy } = useClipboard();
@@ -196,6 +145,82 @@ const menu = useMenu();
 const ai = useAi();
 const Form = useForm();
 
+// 编辑器样式
+monaco.editor.defineTheme("ai-code--dark", {
+	base: "vs-dark",
+	inherit: true,
+	rules: [],
+	colors: {
+		"editor.background": "#0f151e",
+		"editor.inactiveSelectionBackground": "#0f151e"
+	}
+});
+
+// 执行步骤
+const step = reactive({
+	value: "none",
+
+	list: ["none", "coding"],
+
+	next() {
+		const i = step.list.indexOf(step.value);
+
+		if (i < step.list.length - 1) {
+			step.value = step.list[i + 1];
+		}
+	},
+
+	prev() {
+		const i = step.list.indexOf(step.value);
+
+		if (i > 0) {
+			step.value = step.list[i - 1];
+		}
+	}
+});
+
+// 滚动文案
+const desc = reactive({
+	list: ["为开发者生成优质编程代码", "只需少量的口语提示就能完成特定的功能,大大节省开发时间"],
+	text: "",
+
+	init() {
+		function next(n: number) {
+			const val = desc.list[n];
+
+			if (val) {
+				function next2(n2: number) {
+					const v = val[n2];
+
+					if (v) {
+						setTimeout(() => {
+							desc.text += v;
+							next2(n2 + 1);
+						}, 60);
+					} else {
+						setTimeout(() => {
+							const timer = setInterval(() => {
+								desc.text = desc.text.slice(0, -1);
+
+								if (!desc.text) {
+									clearInterval(timer);
+									next(n + 1);
+								}
+							}, 50);
+						}, 1500);
+					}
+				}
+
+				next2(0);
+			} else {
+				next(0);
+			}
+		}
+
+		next(0);
+	}
+});
+
 // 滚动条
 const scroller = {
 	timer: null as any,
@@ -240,14 +265,21 @@ const editor = reactive({
 });
 
 // 表单
-const form = reactive(
-	storage.get("ai-create.form") || {
-		name: "收货地址",
-		module: "user",
-		other: "",
-		columns: "用户ID、联系人、手机号、省市区、地址、是否默认"
-	}
-);
+const form = reactive({
+	list: [
+		{
+			label: "请填写功能名称",
+			desc: "如:收货地址、商品列表、订单列表",
+			loading: false,
+			next() {}
+		},
+		{
+			desc: "请填写功能名称,如:收货地址、商品列表、订单列表",
+			loading: false,
+			next() {}
+		}
+	]
+});
 
 // 临时数据
 const temp = reactive({
@@ -334,6 +366,10 @@ function reset() {
 
 // 下一步,生成代码
 function next() {
+	step.next();
+
+	return;
+
 	if (!form.module) {
 		return ElMessage.warning("请选择模块");
 	}
@@ -543,6 +579,8 @@ watch(
 );
 
 onMounted(() => {
+	desc.init();
+
 	ai.connect({
 		onMessage(content) {
 			codes[temp.coding] = content;
@@ -564,111 +602,328 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
+$color: #41d1ff;
+
 .ai-code {
 	display: flex;
 	flex-direction: column;
 	align-items: center;
 	position: relative;
+	height: 100vh;
+	overflow: hidden;
+
+	.bg {
+		position: absolute;
+		left: 0;
+		top: 0;
+		height: 100%;
+		width: 100%;
+		background-color: #090c13;
+		display: flex;
+		justify-content: center;
 
-	.head {
-		margin: 5vh 0 50px 0;
-	}
+		.a {
+			background-color: $color;
+			transform: rotate(20deg);
+			right: -10px;
+		}
 
-	.container {
-		width: 1040px;
-		max-width: 100%;
-	}
+		.b {
+			background-color: #4165d7;
+			transform: rotate(-20deg);
+			right: 10px;
+		}
 
-	.form {
-		margin-bottom: 50px;
+		.a,
+		.b {
+			height: 300px;
+			width: 420px;
+			position: relative;
+			opacity: 0.4;
+			border-radius: 100%;
+			filter: blur(60px);
+			top: 120px;
+			animation: fb 5s ease-in-out infinite;
+		}
 
-		.label {
-			margin-bottom: 10px;
-			font: 15px;
-			color: var(--el-text-fill-color);
+		@keyframes fb {
+			0% {
+				filter: blur(60px);
+			}
 
-			&.required {
-				&::after {
-					content: "*";
-					margin-left: 2px;
-				}
+			40% {
+				filter: blur(150px);
 			}
-		}
 
-		.el-col {
-			margin-bottom: 10px;
+			80% {
+				filter: blur(60px);
+			}
+
+			100% {
+				filter: blur(60px);
+			}
 		}
 	}
 
-	.codes {
-		margin: 50px 0 0 0;
+	.panels {
+		position: relative;
+		z-index: 2;
 
-		.item {
-			margin-bottom: 20px;
+		.editor {
+			border-radius: 6px;
+			overflow: hidden;
+			background-color: #080e14;
+			margin-bottom: 60px;
 
-			.label {
+			.topbar {
 				display: flex;
 				align-items: center;
-				margin-bottom: 10px;
-				padding-left: 2px;
+				height: 36px;
+				padding: 0 12px;
 
-				.name {
+				.dots {
 					display: flex;
-					align-items: center;
-					font-size: 18px;
-					font-weight: bold;
-					flex: 1;
-					line-height: 1;
+
+					span {
+						display: inline-block;
+						height: 12px;
+						width: 12px;
+						border-radius: 12px;
+						background-color: #2f3447;
+						margin-right: 8px;
+					}
 				}
+			}
 
-				.el-button {
-					margin-left: 10px;
+			.content {
+				background-color: #0f151e;
+
+				:deep(.el-input__wrapper) {
+					background-color: transparent;
+					box-shadow: none;
+					padding: 10px;
+
+					.el-input__inner {
+						color: #fff;
+					}
 				}
 			}
 		}
 
-		.row {
-			display: flex;
-			margin: 0 -10px 30px -10px;
+		.panel-free {
+			height: 100vh;
+			width: 1040px;
+			max-width: 100%;
+			flex-shrink: 0;
+
+			.editor {
+				box-shadow: 0 0 1px 1px rgba($color, 0.7);
+
+				.form {
+					height: 300px;
 
-			.item {
-				flex: 1;
-				margin: 0 10px;
+					&-item {
+						.label {
+							color: #fff;
+						}
+					}
+				}
 			}
-		}
-	}
 
-	.btns {
-		display: flex;
-		justify-content: center;
+			.head {
+				padding: 260px 0 50px 0;
+				text-align: center;
+				color: #fff;
+				line-height: 1;
+				letter-spacing: 2px;
+				user-select: none;
+
+				.title {
+					display: inline-block;
+					font-size: 40px;
+					background-clip: text;
+					font-weight: bold;
+					text-shadow: 0 5px 10px #333;
+					transition: all 0.3s;
+					transition-delay: 0.2s;
+				}
+
+				.tag {
+					margin-top: 30px;
+					font-size: 22px;
+
+					span {
+						color: $color;
+						padding: 0 2px;
+					}
+				}
+
+				.desc {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					height: 35px;
+					padding: 0 1px;
+					color: #fff;
+					font-size: 22px;
+					margin-top: 60px;
+
+					&::after {
+						content: "";
+						display: inline-block;
+						margin-left: 4px;
+						height: 22px;
+						width: 3px;
+						background-color: #fff;
+						border-radius: 3px;
+						animation: shan 1s ease infinite;
+					}
+
+					@keyframes shan {
+						0% {
+							opacity: 0;
+						}
 
-		.el-button {
-			padding: 0 40px;
-			font-size: 15px;
+						50% {
+							opacity: 1;
+						}
+
+						100% {
+							opacity: 0;
+						}
+					}
+				}
+			}
+
+			.btns {
+				display: flex;
+				justify-content: center;
+
+				.el-button {
+					padding: 0 40px;
+					font-size: 15px;
+				}
+			}
+
+			.tips {
+				color: var(--el-text-color-secondary);
+				text-align: center;
+				font-size: 14px;
+				margin: 30px 0;
+				user-select: none;
+			}
 		}
-	}
 
-	.op {
-		display: flex;
-		justify-content: center;
-		position: sticky;
-		bottom: 10px;
-		z-index: 9;
+		.panel-code {
+			position: absolute;
+			bottom: 0;
+			left: -100px;
+			height: 0;
+			width: calc(100% + 200px);
+			background-color: #090c13;
+			border-radius: 12px 12px 0 0;
+			border: 5px solid rgba(255, 255, 255, 0.1);
+			border-bottom: 0;
+			box-sizing: border-box;
+			transition: height 0.5s ease-in-out;
+			overflow: hidden;
+
+			.editor {
+				height: 100%;
+				overflow: hidden;
+
+				.topbar {
+					.dots {
+						span {
+							cursor: pointer;
+
+							&:first-child {
+								&:hover {
+									background-color: var(--el-color-danger);
+								}
+							}
+						}
+					}
 
-		.el-button {
-			padding: 0 20px;
+					.print {
+						display: flex;
+						align-items: center;
+						margin-left: auto;
+						color: #fff;
+
+						.el-icon {
+							margin-right: 5px;
+							font-size: 15px;
+						}
+					}
+				}
+
+				.content {
+					height: calc(100% - 36px);
+
+					.tabs {
+						display: flex;
+						height: 40px;
+						background-color: #080e14;
+
+						.item {
+							display: flex;
+							align-items: center;
+							justify-content: center;
+							padding: 0 15px;
+							font-size: 12px;
+							cursor: pointer;
+							color: var(--el-color-info);
+
+							&.active {
+								background-color: #0f151e;
+								color: #fff;
+							}
+
+							&:hover {
+								color: #eee;
+							}
+						}
+
+						.op {
+							display: flex;
+							align-items: center;
+							margin-left: auto;
+							margin-right: 5px;
+
+							.el-icon {
+								height: 30px;
+								width: 30px;
+								color: #fff;
+								font-size: 18px;
+								cursor: pointer;
+								border-radius: 5px;
+
+								&:hover {
+									background-color: #0f151e;
+								}
+							}
+						}
+					}
+
+					.code {
+						height: calc(100% - 40px);
+					}
+				}
+			}
 		}
-	}
 
-	.tips {
-		color: var(--el-text-color-secondary);
-		text-align: center;
-		font-size: 14px;
-		margin: 30px 0;
-	}
+		&.is-coding {
+			.panel-free {
+				.title {
+					transform: translateY(-130px);
+				}
+			}
 
-	.bottom {
-		height: 10vh;
+			.panel-code {
+				height: calc(100% - 230px);
+			}
+		}
 	}
 }
 </style>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません