This commit is contained in:
神仙都没用 2024-06-25 22:47:41 +08:00
parent 34058e4089
commit 1ff3964f28
6 changed files with 2991 additions and 621 deletions

2859
build/cool/eps.d.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

After

Width:  |  Height:  |  Size: 915 B

View File

@ -1,174 +1,123 @@
<template> <template>
<el-scrollbar :ref="setRefs('scrollbar')"> <el-scrollbar :ref="setRefs('scrollbar')">
<div class="ai-code"> <div class="ai-code">
<div class="container"> <div class="bg">
<div class="head"> <div class="a"></div>
<text2 model-value="Cool Ai 极速编码" /> <div class="b"></div>
</div> </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="editor">
<div class="topbar">
<div class="dots">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="content">
<div class="form"> <div class="form">
<el-form :disabled="temp.disabled" size="large"> <div
<div class="label required">CRUD</div> class="form-item"
v-for="(item, index) in form.list"
:key="index"
>
<p class="label">{{ item.label }}</p>
<el-row :gutter="10"> <el-input resize="none" :placeholder="item.desc">
<el-col :lg="6" :xs="24" :sm="12"> <template #prefix>
<cl-select <el-icon>
class="module" <arrow-right />
placeholder="请选择模块" </el-icon>
v-model="form.module" </template>
:options="module.dirs" </el-input>
label-key="name" </div>
value-key="name" </div>
allow-create </div>
/>
</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>
<div class="btns"> <div class="btns">
<el-button <el-button
round
size="large" size="large"
type="primary" color="#41d1ff"
:icon="Promotion" :icon="Promotion"
:disabled="temp.disabled" :disabled="temp.disabled"
:loading="temp.disabled" :loading="temp.disabled"
@click="next" @click="next"
> >
{{ temp.disabled ? "思考中" : codes.entity.length ? "重新生成" : "下一步" }} {{
temp.disabled
? "思考中"
: codes.entity.length
? "重新生成"
: "下一步"
}}
</el-button> </el-button>
</div> </div>
<div class="tips">如遇见 代码缺失请求超时请尝试刷新</div> <div class="tips">如遇见 代码缺失请求超时请尝试刷新</div>
</div>
<!-- 代码 --> <div class="panel-code">
<div class="codes"> <div class="editor">
<div class="item is-entity" v-show="codes.entity"> <div class="topbar">
<div class="label"> <div class="dots">
<div class="name"> <span @click="step.prev"></span>
<span>Entity实体类</span> <span></span>
<el-icon class="is-loading" v-show="temp.coding == 'entity'"> <span></span>
<loading /> </div>
<div class="print">
<el-icon class="is-loading">
<refresh />
</el-icon>
<span>生成 vue 代码中</span>
</div>
</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> </el-icon>
</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()"
>
生成Vue代码
</el-button>
</template>
</div> </div>
<cl-editor <div class="code">
name="cl-editor-monaco" <cl-editor-monaco
:ref="setRefs('codeEntity')" height="100%"
:options="editor.options" :border="false"
height="auto" :options="{
autofocus theme: 'ai-code--dark'
autosize }"
language="typescript"
v-model="codes.entity"
/> />
</div> </div>
<div class="item is-controller" v-show="codes.controller"> <!-- <div class="op">
<div class="label"> <el-button :icon="CloseBold" @click="reset"> 取消 </el-button>
<div class="name"> <el-button color="#41d1ff" @click="createFile">
<span>Controller控制层</span>
<el-icon class="is-loading" v-show="temp.coding == 'controller'">
<loading />
</el-icon>
</div>
<template v-if="!temp.disabled">
<el-button round size="small" @click="copyCode('controller')"
>Copy</el-button
>
</template>
</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="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>
<template v-if="!temp.disabled">
<el-button round size="small" @click="copyCode('vue')"
>Copy</el-button
>
</template>
</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> </el-button>
</div> -->
</div>
</div>
</div> </div>
<div class="bottom"></div>
</div> </div>
<!-- 创建菜单 --> <!-- 创建菜单 -->
@ -179,8 +128,8 @@
<script lang="tsx" setup name="helper-ai-code"> <script lang="tsx" setup name="helper-ai-code">
import { onMounted, reactive, watch } from "vue"; import { onMounted, reactive, watch } from "vue";
import { module, useCool, storage } from "/@/cool"; import { useCool, storage } from "/@/cool";
import { Promotion, Loading, Close, Check } from "@element-plus/icons-vue"; import { Promotion, Refresh, Download, ArrowRight } from "@element-plus/icons-vue";
import { ElLoading, ElMessage, ElMessageBox } from "element-plus"; import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
import { debounce, isEmpty } from "lodash-es"; import { debounce, isEmpty } from "lodash-es";
import { useClipboard } from "@vueuse/core"; import { useClipboard } from "@vueuse/core";
@ -188,7 +137,7 @@ import { useMenu, useAi } from "../hooks";
import { isDev } from "/@/config"; import { isDev } from "/@/config";
import { useForm } from "@cool-vue/crud"; import { useForm } from "@cool-vue/crud";
import type { CodeType } from "../types"; import type { CodeType } from "../types";
import Text2 from "../components/text.vue"; import * as monaco from "monaco-editor";
const { service, refs, setRefs } = useCool(); const { service, refs, setRefs } = useCool();
const { copy } = useClipboard(); const { copy } = useClipboard();
@ -196,6 +145,82 @@ const menu = useMenu();
const ai = useAi(); const ai = useAi();
const Form = useForm(); 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 = { const scroller = {
timer: null as any, timer: null as any,
@ -240,14 +265,21 @@ const editor = reactive({
}); });
// //
const form = reactive( const form = reactive({
storage.get("ai-create.form") || { list: [
name: "收货地址", {
module: "user", label: "请填写功能名称",
other: "", desc: "如:收货地址、商品列表、订单列表",
columns: "用户ID、联系人、手机号、省市区、地址、是否默认" loading: false,
next() {}
},
{
desc: "请填写功能名称,如:收货地址、商品列表、订单列表",
loading: false,
next() {}
} }
); ]
});
// //
const temp = reactive({ const temp = reactive({
@ -334,6 +366,10 @@ function reset() {
// //
function next() { function next() {
step.next();
return;
if (!form.module) { if (!form.module) {
return ElMessage.warning("请选择模块"); return ElMessage.warning("请选择模块");
} }
@ -543,6 +579,8 @@ watch(
); );
onMounted(() => { onMounted(() => {
desc.init();
ai.connect({ ai.connect({
onMessage(content) { onMessage(content) {
codes[temp.coding] = content; codes[temp.coding] = content;
@ -564,76 +602,195 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$color: #41d1ff;
.ai-code { .ai-code {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
position: relative; position: relative;
height: 100vh;
overflow: hidden;
.head { .bg {
margin: 5vh 0 50px 0; position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
background-color: #090c13;
display: flex;
justify-content: center;
.a {
background-color: $color;
transform: rotate(20deg);
right: -10px;
} }
.container { .b {
background-color: #4165d7;
transform: rotate(-20deg);
right: 10px;
}
.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;
}
@keyframes fb {
0% {
filter: blur(60px);
}
40% {
filter: blur(150px);
}
80% {
filter: blur(60px);
}
100% {
filter: blur(60px);
}
}
}
.panels {
position: relative;
z-index: 2;
.editor {
border-radius: 6px;
overflow: hidden;
background-color: #080e14;
margin-bottom: 60px;
.topbar {
display: flex;
align-items: center;
height: 36px;
padding: 0 12px;
.dots {
display: flex;
span {
display: inline-block;
height: 12px;
width: 12px;
border-radius: 12px;
background-color: #2f3447;
margin-right: 8px;
}
}
}
.content {
background-color: #0f151e;
:deep(.el-input__wrapper) {
background-color: transparent;
box-shadow: none;
padding: 10px;
.el-input__inner {
color: #fff;
}
}
}
}
.panel-free {
height: 100vh;
width: 1040px; width: 1040px;
max-width: 100%; max-width: 100%;
} flex-shrink: 0;
.editor {
box-shadow: 0 0 1px 1px rgba($color, 0.7);
.form { .form {
margin-bottom: 50px; height: 300px;
&-item {
.label { .label {
margin-bottom: 10px; color: #fff;
font: 15px; }
color: var(--el-text-fill-color);
&.required {
&::after {
content: "*";
margin-left: 2px;
} }
} }
} }
.el-col { .head {
margin-bottom: 10px; padding: 260px 0 50px 0;
} text-align: center;
} color: #fff;
.codes {
margin: 50px 0 0 0;
.item {
margin-bottom: 20px;
.label {
display: flex;
align-items: center;
margin-bottom: 10px;
padding-left: 2px;
.name {
display: flex;
align-items: center;
font-size: 18px;
font-weight: bold;
flex: 1;
line-height: 1; 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;
} }
.el-button { .tag {
margin-left: 10px; margin-top: 30px;
} font-size: 22px;
span {
color: $color;
padding: 0 2px;
} }
} }
.row { .desc {
display: flex; display: flex;
margin: 0 -10px 30px -10px; align-items: center;
justify-content: center;
height: 35px;
padding: 0 1px;
color: #fff;
font-size: 22px;
margin-top: 60px;
.item { &::after {
flex: 1; content: "";
margin: 0 10px; 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;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
} }
} }
} }
@ -648,27 +805,125 @@ onMounted(() => {
} }
} }
.op {
display: flex;
justify-content: center;
position: sticky;
bottom: 10px;
z-index: 9;
.el-button {
padding: 0 20px;
}
}
.tips { .tips {
color: var(--el-text-color-secondary); color: var(--el-text-color-secondary);
text-align: center; text-align: center;
font-size: 14px; font-size: 14px;
margin: 30px 0; margin: 30px 0;
user-select: none;
}
} }
.bottom { .panel-code {
height: 10vh; 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);
}
}
}
}
.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);
}
}
}
}
&.is-coding {
.panel-free {
.title {
transform: translateY(-130px);
}
}
.panel-code {
height: calc(100% - 230px);
}
}
} }
} }
</style> </style>