优化视图的滚动方法

This commit is contained in:
icssoa 2024-02-19 18:22:10 +08:00
parent 7aee76cbd0
commit eb452189ea
10 changed files with 443 additions and 421 deletions

View File

@ -1,13 +1,11 @@
<template>
<div class="app-views">
<router-view v-slot="{ Component }">
<el-scrollbar :ref="setRefs('scrollbar')" :key="key">
<transition :name="app.info.router.transition || 'none'">
<keep-alive :include="caches">
<component :is="Component" />
</keep-alive>
</transition>
</el-scrollbar>
<transition :name="app.info.router.transition || 'none'">
<keep-alive :include="caches" :key="key">
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
</div>
</template>
@ -17,7 +15,7 @@ import { computed, onMounted, onUnmounted, ref } from "vue";
import { useBase } from "/$/base";
import { useCool } from "/@/cool";
const { refs, setRefs, mitt } = useCool();
const { mitt } = useCool();
const { process, app } = useBase();
//
@ -37,27 +35,11 @@ function refresh() {
key.value += 1;
}
//
function scrollTo({ el, top }: { el?: string; top?: number }) {
const scrollbar = refs.scrollbar.wrapRef;
if (el) {
top = scrollbar.querySelector(el).offsetTop;
}
scrollbar.scrollTo({
top,
behavior: "smooth"
});
}
onMounted(() => {
mitt.on("view.scrollTo", scrollTo);
mitt.on("view.refresh", refresh);
});
onUnmounted(() => {
mitt.off("view.scrollTo");
mitt.off("view.refresh");
});
</script>
@ -72,10 +54,6 @@ onUnmounted(() => {
border-radius: 4px;
position: relative;
:deep(.el-scrollbar__view) {
height: 100%;
}
.none-enter-active {
position: absolute;
}

View File

@ -1,16 +1,3 @@
*::-webkit-scrollbar {
width: 10px;
height: 10px;
}
*::-webkit-scrollbar-thumb {
background-color: rgba(144, 147, 153, 0.3);
}
*::-webkit-scrollbar-track {
background: transparent;
}
#app {
height: 100vh;
width: 100vw;

View File

@ -1,54 +1,56 @@
<template>
<div class="view-home">
<el-row :gutter="15">
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-user />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-views />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-paid />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-effect />
</div>
</el-col>
</el-row>
<el-scrollbar>
<div class="view-home">
<el-row :gutter="15">
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-user />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-views />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-paid />
</div>
</el-col>
<el-col :lg="6" :md="12" :xs="24">
<div class="card">
<count-effect />
</div>
</el-col>
</el-row>
<el-row :gutter="15">
<el-col :lg="14" :xs="24">
<div class="card">
<tab-chart />
</div>
</el-col>
<el-col :lg="10" :xs="24">
<div class="card">
<sales-rank />
</div>
</el-col>
</el-row>
<el-row :gutter="15">
<el-col :lg="14" :xs="24">
<div class="card">
<tab-chart />
</div>
</el-col>
<el-col :lg="10" :xs="24">
<div class="card">
<sales-rank />
</div>
</el-col>
</el-row>
<el-row :gutter="15">
<el-col :lg="14" :sm="24">
<div class="card card--last">
<hot-search />
</div>
</el-col>
<el-col :lg="10" :sm="24">
<div class="card card--last">
<category-ratio />
</div>
</el-col>
</el-row>
</div>
<el-row :gutter="15">
<el-col :lg="14" :sm="24">
<div class="card card--last">
<hot-search />
</div>
</el-col>
<el-col :lg="10" :sm="24">
<div class="card card--last">
<category-ratio />
</div>
</el-col>
</el-row>
</div>
</el-scrollbar>
</template>
<script lang="ts" name="home" setup>

View File

@ -7,10 +7,11 @@
<div class="footer">
<el-button @click="clear">清空</el-button>
<el-button type="info" @click="save">保存草稿</el-button>
<el-button type="success" @click="create">生成代码</el-button>
</div>
<cl-editor-preview title="代码预览" name="monaco" :ref="setRefs('preview')" />
<cl-editor-preview title="代码预览" name="monaco" :ref="setRefs('preview')">
<el-button type="success" @click="create">生成代码</el-button>
</cl-editor-preview>
</div>
</div>
</template>

View File

@ -142,28 +142,3 @@ export function useAi() {
matchType
};
}
export function useScroll() {
const { mitt } = useCool();
let timer: any;
function start() {
stop();
timer = setInterval(() => {
mitt.emit("view.scrollTo", { top: Math.random() + 10000 });
}, 100);
}
function stop() {
if (timer) {
clearInterval(timer);
}
}
return {
start,
stop
};
}

View File

@ -1,9 +1,10 @@
.plugins {
overflow-x: hidden;
background-color: var(--el-bg-color);
padding: 10px;
height: 100%;
box-sizing: border-box;
&__wrapper {
background-color: var(--el-bg-color);
height: 100%;
}
.scope {
border-radius: 8px;

View File

@ -1,176 +1,180 @@
<template>
<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="tips">如遇见 代码缺失请求超时请尝试刷新</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>
<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>
<cl-editor
name="cl-editor-monaco"
:ref="setRefs('codeEntity')"
:options="editor.options"
height="auto"
autofocus
autosize
language="typescript"
v-model="codes.entity"
/>
<el-scrollbar :ref="setRefs('scrollbar')">
<div class="ai-code">
<div class="container">
<div class="head">
<text2 model-value="Cool Ai 极速编码" />
</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>
<div class="form">
<el-form :disabled="temp.disabled" size="large">
<div class="label required">CRUD</div>
<template v-if="!temp.disabled">
<el-button round size="small" @click="copyCode('controller')"
>Copy</el-button
>
</template>
</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>
<cl-editor
name="cl-editor-monaco"
:ref="setRefs('codeController')"
:options="editor.options"
height="auto"
autosize
language="typescript"
v-model="codes.controller"
/>
<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="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="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="tips">如遇见 代码缺失请求超时请尝试刷新</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>
<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>
<template v-if="!temp.disabled">
<el-button round size="small" @click="copyCode('vue')">Copy</el-button>
</template>
<cl-editor
name="cl-editor-monaco"
:ref="setRefs('codeEntity')"
:options="editor.options"
height="auto"
autofocus
autosize
language="typescript"
v-model="codes.entity"
/>
</div>
<cl-editor
name="cl-editor-monaco"
:ref="setRefs('codeVue')"
:options="editor.options"
height="auto"
autosize
language="html"
v-model="codes.vue"
/>
<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>
<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>
</div>
<div class="bottom"></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>
<!-- 创建菜单 -->
<cl-form ref="Form" />
</div>
<!-- 创建菜单 -->
<cl-form ref="Form" />
</div>
</el-scrollbar>
</template>
<script lang="tsx" setup name="helper-ai-code">
@ -180,19 +184,54 @@ import { Promotion, Loading, Close, Check } from "@element-plus/icons-vue";
import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
import { debounce, isEmpty } from "lodash-es";
import { useClipboard } from "@vueuse/core";
import { useMenu, useAi, useScroll } from "../hooks";
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";
const { service, mitt, refs, setRefs } = useCool();
const { service, refs, setRefs } = useCool();
const { copy } = useClipboard();
const menu = useMenu();
const ai = useAi();
const scroll = useScroll();
const Form = useForm();
//
const scroller = {
timer: null as any,
scrollTo({ el, top }: { el?: string; top?: number }) {
const scrollbar = refs.scrollbar.wrapRef;
if (el) {
top = scrollbar.querySelector(el).offsetTop;
}
scrollbar.scrollTo({
top,
behavior: "smooth"
});
},
start() {
this.stop();
this.timer = setInterval(() => {
if (codes.entity) {
this.scrollTo({
top: Math.random() + 10000
});
}
}, 100);
},
stop() {
if (this.timer) {
clearInterval(this.timer);
}
}
};
//
const editor = reactive({
options: {
@ -275,14 +314,14 @@ function send(type: CodeType = "entity", data: any) {
});
//
scroll.start();
scroller.start();
}
//
function stop() {
temp.disabled = false;
temp.coding = "";
scroll.stop();
scroller.stop();
}
//
@ -454,7 +493,7 @@ const createVue = debounce((auto?: boolean) => {
stop();
setTimeout(() => {
mitt.emit("view.scrollTo", { el: `.codes .is-vue` });
scroller.scrollTo({ el: `.codes .is-vue` });
refs.codeVue.formatCode();
}, 300);
}
@ -629,7 +668,7 @@ onMounted(() => {
}
.bottom {
height: 100px;
height: 10vh;
}
}
</style>

View File

@ -1,95 +1,113 @@
<template>
<div class="plugins" @dragover="onDragover" @drop="onDrop">
<el-tabs v-model="tab.active" type="card" @tab-change="tab.onChange">
<el-tab-pane label="已安装插件" name="installed"> </el-tab-pane>
<el-tab-pane label="插件市场" name="shop"> </el-tab-pane>
</el-tabs>
<div class="plugins__wrapper">
<el-scrollbar>
<div class="plugins" @dragover="onDragover" @drop="onDrop">
<el-tabs v-model="tab.active" type="card" @tab-change="tab.onChange">
<el-tab-pane label="已安装插件" name="installed"> </el-tab-pane>
<el-tab-pane label="插件市场" name="shop"> </el-tab-pane>
</el-tabs>
<el-row :gutter="10">
<el-col v-for="(item, index) in list" :key="index" :xs="24" :sm="12" :md="8" :lg="6">
<div class="scope">
<div class="c">
<el-icon class="set" @click="toSet(item)">
<setting />
</el-icon>
<el-row :gutter="10">
<el-col
v-for="(item, index) in list"
:key="index"
:xs="24"
:sm="12"
:md="8"
:lg="6"
>
<div class="scope">
<div class="c">
<el-icon class="set" @click="toSet(item)">
<setting />
</el-icon>
<img class="logo" :src="'data:image/jpg;base64,' + item.logo" />
<img class="logo" :src="'data:image/jpg;base64,' + item.logo" />
<div class="det">
<div class="tag">
<el-tag size="small" effect="dark">{{ item.keyName }}</el-tag>
<el-tag size="small" effect="dark" type="success"
>v{{ item.version }}</el-tag
>
<div class="det">
<div class="tag">
<el-tag size="small" effect="dark">{{
item.keyName
}}</el-tag>
<el-tag size="small" effect="dark" type="success"
>v{{ item.version }}</el-tag
>
</div>
<p class="title">
{{ item.name || "未知" }}
</p>
<p class="desc">{{ item.description || "暂无描述" }}</p>
<div class="author">
<span>{{ item.author }}</span>
<span>{{ item.updateTime }}</span>
</div>
</div>
</div>
<p class="title">
{{ item.name || "未知" }}
</p>
<div class="f">
<el-button round @click="toDetail(item)">详情</el-button>
<el-button type="danger" round @click="toDel(item, index)"
>卸载</el-button
>
<p class="desc">{{ item.description || "暂无描述" }}</p>
<cl-flex1 />
<div class="author">
<span>{{ item.author }}</span>
<span>{{ item.updateTime }}</span>
<cl-switch
v-model="item.status"
@change="onStatusChange(item)"
></cl-switch>
</div>
</div>
</div>
</el-col>
<div class="f">
<el-button round @click="toDetail(item)">详情</el-button>
<el-button type="danger" round @click="toDel(item, index)">卸载</el-button>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<cl-upload :before-upload="onBeforeUpload" accept=".cool">
<div class="scope is-add">
<el-icon>
<plus />
</el-icon>
</div>
</cl-upload>
</el-col>
</el-row>
<cl-flex1 />
<!-- 详情预览 -->
<cl-editor-preview
:ref="setRefs('editorPreview')"
name="wang"
:show-btn="false"
:title="`${info?.name} v${info?.version} 说明文档`"
>
<template #prepend>
<div class="info-header">
<span>作者{{ info?.author }}</span>
<span>更新时间{{ info?.updateTime }}</span>
</div>
</template>
</cl-editor-preview>
<cl-switch v-model="item.status" @change="onStatusChange(item)"></cl-switch>
</div>
</div>
</el-col>
<!-- 设置 -->
<cl-form ref="Form">
<template #slot-upload>
<cl-row>
<cl-upload-space
:show-list="false"
:multiple="false"
text="选择文件"
@confirm="onFileConfirm"
/>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<cl-upload :before-upload="onBeforeUpload" accept=".cool">
<div class="scope is-add">
<el-icon>
<plus />
</el-icon>
</div>
</cl-upload>
</el-col>
</el-row>
<!-- 详情预览 -->
<cl-editor-preview
:ref="setRefs('editorPreview')"
name="wang"
:show-btn="false"
:title="`${info?.name} v${info?.version} 说明文档`"
>
<template #prepend>
<div class="info-header">
<span>作者{{ info?.author }}</span>
<span>更新时间{{ info?.updateTime }}</span>
</div>
</template>
</cl-editor-preview>
<!-- 设置 -->
<cl-form ref="Form">
<template #slot-upload>
<cl-row>
<cl-upload-space
:show-list="false"
:multiple="false"
text="选择文件"
@confirm="onFileConfirm"
/>
<el-text type="warning" :style="{ marginLeft: '10px' }"
>选择后会在光标后插入文件链接</el-text
>
</cl-row>
</template>
</cl-form>
<el-text type="warning" :style="{ marginLeft: '10px' }"
>选择后会在光标后插入文件链接</el-text
>
</cl-row>
</template>
</cl-form>
</div>
</el-scrollbar>
</div>
</template>
@ -137,6 +155,10 @@ function toSet(item: Eps.PluginInfoEntity) {
Form.value?.open({
title: "设置",
props: {
labelWidth: "60px"
},
form: {
...item
},

View File

@ -1,62 +1,79 @@
<template>
<div class="plugins">
<el-tabs v-model="tab.active" type="card" @tab-change="tab.onChange">
<el-tab-pane label="已安装插件" name="installed"> </el-tab-pane>
<el-tab-pane label="插件市场" name="shop"> </el-tab-pane>
</el-tabs>
<el-row :gutter="10">
<el-col v-for="(item, index) in list" :key="index" :xs="24" :sm="12" :md="8" :lg="6">
<div class="scope">
<div class="c">
<img class="logo" :src="item.logo" />
<div class="det">
<div class="tag">
<el-tag size="small" effect="dark">{{ item.name }}</el-tag>
<el-tag size="small" effect="dark" type="success"
>v{{ item.version || "1.0.0" }}</el-tag
>
</div>
<p class="title">
{{ item.label || "未知" }}
</p>
<p class="desc">{{ item.description || "暂无描述" }}</p>
<div class="author">
<span>{{ item.author || "Ta" }}</span>
<span>{{ item.updateTime || "2024-01-01" }}</span>
</div>
</div>
</div>
<div class="f">
<cl-flex1 />
<el-button
round
@click="det.open(item)"
v-if="item.demo && !isEmpty(item.demo)"
>示例</el-button
>
</div>
<div class="plugins__wrapper">
<el-scrollbar>
<div class="plugins">
<div class="header">
<el-tabs v-model="tab.active" type="card" @tab-change="tab.onChange">
<el-tab-pane label="已安装插件" name="installed"> </el-tab-pane>
<el-tab-pane label="插件市场" name="shop"> </el-tab-pane>
</el-tabs>
</div>
</el-col>
</el-row>
<cl-dialog v-model="det.visible" :title="det.title" width="60%">
<el-tabs v-model="det.active" type="card" @tab-change="tab.onChange">
<el-tab-pane
v-for="(item, index) in det.tabs"
:key="index"
:label="item.name"
:name="index"
>
<component :is="item.component" />
</el-tab-pane>
</el-tabs>
</cl-dialog>
<div class="container">
<el-row :gutter="10">
<el-col
v-for="(item, index) in list"
:key="index"
:xs="24"
:sm="12"
:md="8"
:lg="6"
>
<div class="scope">
<div class="c">
<img class="logo" :src="item.logo" />
<div class="det">
<div class="tag">
<el-tag size="small" effect="dark">{{
item.name
}}</el-tag>
<el-tag size="small" effect="dark" type="success"
>v{{ item.version || "1.0.0" }}</el-tag
>
</div>
<p class="title">
{{ item.label || "未知" }}
</p>
<p class="desc">{{ item.description || "暂无描述" }}</p>
<div class="author">
<span>{{ item.author || "Ta" }}</span>
<span>{{ item.updateTime || "2024-01-01" }}</span>
</div>
</div>
</div>
<div class="f">
<cl-flex1 />
<el-button
round
@click="det.open(item)"
v-if="item.demo && !isEmpty(item.demo)"
>示例</el-button
>
</div>
</div>
</el-col>
</el-row>
</div>
<cl-dialog v-model="det.visible" :title="det.title" width="60%">
<el-tabs v-model="det.active" type="card" @tab-change="tab.onChange">
<el-tab-pane
v-for="(item, index) in det.tabs"
:key="index"
:label="item.name"
:name="index"
>
<component :is="item.component" />
</el-tab-pane>
</el-tabs>
</cl-dialog>
</div>
</el-scrollbar>
</div>
</template>

View File

@ -2,6 +2,6 @@
<space-inner />
</template>
<script lang="ts" setup name="space-list">
<script lang="ts" setup name="upload-list">
import SpaceInner from "../components/space-inner.vue";
</script>