2024-07-22 23:13:29 +08:00

352 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-scrollbar class="plugins__wrapper">
<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>
<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>
<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>
<div class="f">
<el-button round @click="toDetail(item)">详情</el-button>
<el-button type="danger" round @click="toDel(item, index)"
>卸载</el-button
>
<cl-flex1 />
<cl-switch
v-model="item.status"
@change="onStatusChange(item)"
></cl-switch>
</div>
</div>
</el-col>
<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>
</div>
</el-scrollbar>
</template>
<script lang="ts" setup name="helper-plugins-serve">
import { onActivated, reactive, ref, nextTick } from "vue";
import { useCool } from "/@/cool";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Setting } from "@element-plus/icons-vue";
import { marked } from "marked";
import { useForm } from "@cool-vue/crud";
import { merge, template } from "lodash-es";
const { service, refs, setRefs } = useCool();
const Form = useForm();
// 选项卡
const tab = reactive({
active: "installed",
onChange(val: string) {
if (val == "shop") {
nextTick(() => {
tab.active = "installed";
window.open("https://cool-js.com/plugin");
});
}
}
});
// 插件列表
const list = ref<Eps.PluginInfoEntity[]>([]);
// 插槽详情
const info = ref<Eps.PluginInfoEntity>();
// 刷新
function refresh() {
service.plugin.info.page().then((res) => {
list.value = res.list;
});
}
// 参数设置
function toSet(item: Eps.PluginInfoEntity) {
Form.value?.open({
title: "设置",
props: {
labelWidth: "60px"
},
form: {
...item
},
items: [
{
label: "参数",
prop: "config",
value: "{}",
component: {
name: "cl-editor",
props: {
name: "cl-editor-monaco",
ref: setRefs("editor")
}
}
},
{
label: " ",
flex: false,
component: {
name: "slot-upload"
}
},
{
label: "状态",
prop: "status",
component: {
name: "cl-switch"
}
}
],
on: {
submit(data, { done, close }) {
try {
const config = JSON.parse(data.config);
service.plugin.info
.update({
config,
id: data.id,
status: data.status
})
.then(() => {
ElMessage.success("修改成功");
merge(item, data);
close();
})
.catch((err) => {
ElMessage.error(err.message);
done();
});
} catch (e) {
ElMessage.error("参数格式错误,请检查");
done();
}
}
}
});
}
// 详情
async function toDetail(item: Eps.PluginInfoEntity) {
info.value = item;
refs.editorPreview.open(await marked.parse(item.readme!));
}
// 卸载
function toDel(item: Eps.PluginInfoEntity, index: number) {
ElMessageBox.confirm(`确定要卸载插件【${item.name}】吗?`, "提示", {
type: "warning"
})
.then(() => {
service.plugin.info
.delete({
ids: [item.id]
})
.then(() => {
list.value.splice(index, 1);
ElMessage.success("卸载成功");
})
.catch((err) => {
ElMessage.error(err.message);
});
})
.catch(() => null);
}
// 文件选择
function onFileConfirm(arr: any[]) {
refs.editor.appendContent(arr[0]?.url);
}
// 状态修改
function onStatusChange(item: Eps.PluginInfoEntity) {
service.plugin.info
.update({
id: item.id,
status: item.status
})
.then(() => {
ElMessage.success(item.status ? "开启成功" : "关闭成功");
})
.catch((err) => {
ElMessage.error(err.message);
});
}
// 上传
function onBeforeUpload(file: File) {
function next(force: string) {
const formData = new FormData();
formData.append("files", file);
formData.append("force", force);
service.plugin.info
.request({
url: "/install",
method: "POST",
data: formData,
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((res) => {
if (res) {
ElMessageBox.confirm(res.message, "提示", {
type: "warning",
confirmButtonText: "继续"
})
.then(() => {
next("true");
})
.catch(() => null);
} else {
ElMessage.success("插件安装成功");
refresh();
}
})
.catch((err) => {
ElMessage.error(err.message);
});
}
next("false");
return false;
}
// 拖拽
function onDragover(e: DragEvent) {
e.preventDefault();
}
// 放下
function onDrop(e: DragEvent) {
e.preventDefault();
if (e.dataTransfer) {
const file = e.dataTransfer.files[0];
ElMessageBox.confirm("检测到插件,是否安装", "提示", {
type: "warning",
confirmButtonText: "安装"
})
.then(() => {
onBeforeUpload(file);
})
.catch(() => null);
}
}
onActivated(() => {
refresh();
});
</script>
<style lang="scss" scoped>
@import "../../static/index.scss";
.info-header {
display: flex;
align-items: center;
font-size: 13px;
margin-bottom: 15px;
span {
margin-right: 20px;
line-height: 1;
}
}
</style>