2024-12-16 22:04:05 +08:00
|
|
|
<template>
|
|
|
|
<div class="system-menu-dialog-container">
|
|
|
|
<el-dialog @close="closeDialog" :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
|
|
|
<el-form v-loading="state.loading" ref="applyDialogFormRef" :model="state.data" :rules="state.rules" size="default" label-width="100px">
|
|
|
|
<el-row :gutter="35">
|
|
|
|
<el-col :xs="24" :sm="10" :md="10" :lg="10" :xl="10" class="mb20">
|
|
|
|
<el-form-item label="图标:" class="iconImg">
|
|
|
|
<!-- 上传文件 -->
|
|
|
|
<el-upload ref="uploadRef" class="h100 personal-user-left-upload" action="#" list-type="picture-card" :file-list="state.fileArray"
|
|
|
|
:auto-upload="false" :limit="1" :class="{ hide: state.coverHide }" @change="handleUploadChange" accept='image/*'>
|
|
|
|
<template #default>
|
|
|
|
<el-icon><Plus /></el-icon>
|
|
|
|
</template>
|
|
|
|
<template #file="{ file }">
|
|
|
|
<div>
|
|
|
|
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
|
|
|
|
<span class="el-upload-list__item-actions">
|
|
|
|
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
|
|
|
|
<el-icon><zoom-in /></el-icon>
|
|
|
|
</span>
|
|
|
|
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
|
|
|
|
<el-icon><Delete /></el-icon>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</el-upload>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
|
|
<el-form-item label="应用名称:" prop="name">
|
|
|
|
<el-input v-model="state.data.name" placeholder="请输入应用名称" clearable></el-input>
|
|
|
|
</el-form-item>
|
|
|
|
<el-form-item label="接口名:" prop="api">
|
|
|
|
<el-input v-model="state.data.api" placeholder="请输入接口名" clearable></el-input>
|
|
|
|
</el-form-item>
|
|
|
|
<el-form-item label="提示词:" prop="tips">
|
|
|
|
<el-input v-model="state.data.tips" placeholder="请输入提示词" clearable></el-input>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
</el-row>
|
|
|
|
<el-row :gutter="35">
|
|
|
|
<el-col :xs="24" :sm="10" :md="8" :lg="8" :xl="8" class="mb20">
|
|
|
|
<el-form-item label="价格:" prop="price">
|
|
|
|
<el-input-number v-model="state.data.price" :min="0" controls-position="right">
|
|
|
|
<template #prefix><span>¥</span></template>
|
|
|
|
</el-input-number>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20">
|
|
|
|
<el-form-item label="排序号:" prop="position">
|
|
|
|
<el-input-number v-model="state.data.position" :min="1" controls-position="right" />
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
<el-col :xs="24" :sm="10" :md="8" :lg="8" :xl="8" class="mb20">
|
|
|
|
<el-form-item label="类型:" prop="type">
|
|
|
|
<el-select size="default" v-model="state.data.type" placeholder="请选择应用类型" clearable>
|
|
|
|
<el-option v-for="(item,index) in typeList" :key="index" :label="item.name" :value="item.id"></el-option>
|
|
|
|
</el-select>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20">
|
|
|
|
<el-form-item label="是否上架:" prop="publish">
|
|
|
|
<el-switch v-model="state.data.publish" />
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
2024-12-23 14:22:39 +08:00
|
|
|
<el-col :xs="24" :sm="16" :md="12" :lg="12" :xl="12" class="mb20">
|
|
|
|
<el-form-item label="使用教程:">
|
|
|
|
<el-input v-model="state.data.exampleUrl" placeholder="请输入使用教程链接" clearable></el-input>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
2024-12-16 22:04:05 +08:00
|
|
|
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16" class="mb20" v-if="state.data.options&&state.data.options.length>0">
|
|
|
|
<el-form-item label="选项:">
|
|
|
|
<div class="tags-option">
|
|
|
|
<el-tag v-for="option in state.data.options" :key="option.id" :disable-transitions="false">{{ option.optionName }}</el-tag>
|
|
|
|
</div>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
</el-row>
|
|
|
|
</el-form>
|
|
|
|
<template #footer>
|
|
|
|
<span class="dialog-footer">
|
|
|
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
|
|
<el-button size="danger" plain v-if="state.dialog.type === 'edit'" @click="deleteApply">删 除</el-button>
|
|
|
|
<el-button type="primary" plain @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
|
|
|
</span>
|
|
|
|
</template>
|
|
|
|
</el-dialog>
|
|
|
|
<!-- 封面预览弹窗 -->
|
|
|
|
<el-dialog v-model="dialogVisible">
|
|
|
|
<img width="100%" w-full :src="dialogImageUrl" alt="预览" />
|
|
|
|
</el-dialog>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts" name="applyDialog">
|
|
|
|
import { ElMessage, ElMessageBox, UploadFile, UploadFiles } from 'element-plus';
|
|
|
|
import { applyApi } from '/@/api/service/apply';
|
|
|
|
import { articleApi } from '/@/api/article';
|
|
|
|
import { Delete, Plus, ZoomIn } from '@element-plus/icons-vue';
|
|
|
|
import { reactive, ref } from 'vue';
|
|
|
|
|
|
|
|
// 定义子组件向父组件传值/事件
|
|
|
|
const emit = defineEmits(['refresh']);
|
|
|
|
|
|
|
|
// 定义变量内容
|
|
|
|
const applyDialogFormRef = ref();
|
|
|
|
const state:any = reactive({
|
|
|
|
data: {
|
|
|
|
},
|
|
|
|
dialog: {
|
|
|
|
isShowDialog: false,
|
|
|
|
type: '',
|
|
|
|
title: '',
|
|
|
|
submitTxt: '',
|
|
|
|
},
|
|
|
|
loading: false,
|
|
|
|
rules: {
|
|
|
|
name: { required: true, message: '请输入应用名称', trigger: 'blur' },
|
|
|
|
api: { required: true, message: '请输入接口名', trigger: 'blur' },
|
|
|
|
tips: { required: true, message: '请输入提示词', trigger: 'blur' },
|
|
|
|
price: { required: true, message: '请输入价格', trigger: 'blur' },
|
|
|
|
position: { required: true, message: '请输入排序号', trigger: 'blur' },
|
|
|
|
type: { required: true, message: '请选择应用类型', trigger: 'blur' },
|
|
|
|
},
|
|
|
|
fileArray:[],// 编辑进来时,如果已经上传了图片,则保存图片地址
|
|
|
|
coverFile: {},
|
|
|
|
coverHide: false
|
|
|
|
});
|
|
|
|
// 类型列表
|
|
|
|
const typeList = ref([
|
|
|
|
{id: '0',name: '图生图'},
|
|
|
|
{id: '1',name: '文生图'},
|
|
|
|
{id: '2',name: '选项+图片'},
|
|
|
|
{id: '3',name: '选项+文字'},
|
|
|
|
{id: '4',name: '换装'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// 引入 api 请求接口
|
|
|
|
const aplApi = applyApi();
|
|
|
|
const artApi = articleApi();
|
|
|
|
|
|
|
|
// 图标上传禁用
|
|
|
|
const disabled = ref(false);
|
|
|
|
// 图标弹窗
|
|
|
|
const dialogImageUrl = ref('');
|
|
|
|
const dialogVisible = ref(false);
|
|
|
|
// 基本路径
|
|
|
|
const viteUrl = import.meta.env.VITE_API_URL;
|
|
|
|
// upload/Attachment/20241207/0fb6372ed5cd4fb9be68315301093f57.png
|
|
|
|
const defaultIcon:string = 'static/pixel/home/default-work.png';
|
|
|
|
|
|
|
|
const uploadRef = ref();
|
|
|
|
|
|
|
|
// 图标图片更改
|
|
|
|
const handleUploadChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
|
|
|
if(uploadFile.raw.type.includes('image')){
|
|
|
|
const file:any = uploadFile.raw;
|
|
|
|
state.coverFile = file;
|
|
|
|
state.coverHide = true;
|
|
|
|
}else{
|
|
|
|
ElMessage.error('请上传图片文件!');
|
|
|
|
uploadRef.value.clearFiles();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 图标删除
|
|
|
|
const handleRemove = (file?: UploadFile) => {
|
|
|
|
state.coverFile = {};
|
|
|
|
uploadRef.value.clearFiles();
|
|
|
|
state.coverHide = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 图标预览
|
|
|
|
const handlePictureCardPreview = (file: UploadFile) => {
|
|
|
|
dialogImageUrl.value = file.url!
|
|
|
|
dialogVisible.value = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取详情
|
|
|
|
const getData = (id: number) => {
|
|
|
|
try {
|
|
|
|
state.loading = true;
|
|
|
|
aplApi.getApplyDetail(id).then((res: any) => {
|
|
|
|
if(!res?.success){
|
|
|
|
ElMessage.error('服务详情获取失败!');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state.data = res.data;
|
|
|
|
state.data.publish = res.data.publish === 1;
|
|
|
|
const never:any = [{name:res.data.name,url:encodeURI(viteUrl+(res.data.icon||defaultIcon))}];
|
|
|
|
state.fileArray = never;
|
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
ElMessage.error('服务详情获取失败!');
|
|
|
|
} finally {
|
|
|
|
state.loading = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 打开弹窗
|
|
|
|
const openDialog = (type: string, row?: any) => {
|
|
|
|
if (type === 'edit') {
|
|
|
|
getData(row.id);
|
|
|
|
state.dialog.title = '修改应用';
|
|
|
|
state.dialog.submitTxt = '修 改';
|
|
|
|
state.coverHide = true;
|
|
|
|
} else {
|
|
|
|
state.dialog.title = '新增应用';
|
|
|
|
state.dialog.submitTxt = '新 增';
|
|
|
|
}
|
|
|
|
state.dialog.type = type;
|
|
|
|
state.dialog.isShowDialog = true;
|
|
|
|
};
|
|
|
|
// 关闭弹窗
|
|
|
|
const closeDialog = () => {
|
|
|
|
setTimeout(() => {
|
|
|
|
state.dialog.isShowDialog = false;
|
|
|
|
state.data = {};
|
|
|
|
state.fileArray = [];
|
|
|
|
handleRemove();
|
|
|
|
}, 300)
|
|
|
|
};
|
|
|
|
// 取消
|
|
|
|
const onCancel = () => {
|
|
|
|
closeDialog();
|
|
|
|
};
|
|
|
|
// 删除应用服务
|
|
|
|
const deleteApply = () => {
|
|
|
|
ElMessageBox.confirm(`确定要删除${state.data.name}吗?`, '提示', {
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
type: 'warning',
|
|
|
|
})
|
|
|
|
.then(async() => {
|
|
|
|
try {
|
|
|
|
state.loading = true;
|
|
|
|
let res = await aplApi.deleteApply(state.data.id);
|
|
|
|
if(res?.success){
|
|
|
|
ElMessage.success(`${state.data.name}删除成功!`);
|
|
|
|
closeDialog(); // 关闭弹窗
|
|
|
|
emit('refresh');
|
|
|
|
} else ElMessage.error(`${state.data.name}删除失败!`);
|
|
|
|
} catch(e) {
|
|
|
|
ElMessage.error('处理失败!');
|
|
|
|
} finally {
|
|
|
|
state.loading = false;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
// 上传文件
|
|
|
|
const uploadFile = async(file: any,form: any) => {
|
|
|
|
try {
|
|
|
|
state.loading = true;
|
|
|
|
const formdata = new FormData();
|
|
|
|
formdata.append('file', file);
|
|
|
|
let res = await artApi.uploadFile(formdata);
|
|
|
|
if(res?.success){
|
|
|
|
form.icon = res.data.path;
|
|
|
|
realSubmit(form);
|
|
|
|
}else{
|
|
|
|
ElMessage.error('封面上传失败!');
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
state.loading = false;
|
|
|
|
ElMessage.error('封面上传失败!');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 提交
|
|
|
|
const onSubmit = () => {
|
|
|
|
applyDialogFormRef.value.validate((valid: boolean) => {
|
|
|
|
if (valid && state.coverHide){
|
|
|
|
const form = {...state.data,publish:state.data.publish ? 1 : 0};
|
|
|
|
|
|
|
|
if(state.coverFile.type === undefined){
|
|
|
|
realSubmit(form);
|
|
|
|
}else{
|
|
|
|
uploadFile(state.coverFile,form);
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
ElMessage.error('请完善信息!');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// 应用服务上传-真正的上传操作
|
|
|
|
const realSubmit = async(form: any) => {
|
|
|
|
try {
|
|
|
|
state.loading = true;
|
|
|
|
let res = state.dialog.type === 'add' ? await aplApi.saveApply(form) : await aplApi.updateApply(form);
|
|
|
|
if(res?.success){
|
|
|
|
ElMessage.success('应用服务保存成功!');
|
|
|
|
closeDialog(); // 关闭弹窗
|
|
|
|
emit('refresh');
|
|
|
|
}else{
|
|
|
|
ElMessage.error('应用服务保存失败!');
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
ElMessage.error('处理失败!');
|
|
|
|
} finally {
|
|
|
|
state.loading = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 暴露变量
|
|
|
|
defineExpose({
|
|
|
|
openDialog,
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.iconImg :deep(.hide .el-upload--picture-card) {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
.tags-option{
|
|
|
|
width: 100%;
|
|
|
|
height: 90px;
|
|
|
|
overflow-y: scroll;
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(50px,100px) );
|
|
|
|
grid-gap: 0.4em 0.8em;
|
|
|
|
// grid-auto-flow: column dense;
|
|
|
|
}
|
|
|
|
</style>
|