chore(config): 初始化项目配置文件
- 添加 .editorconfig 文件统一代码风格 - 配置 .env.development 环境变量文件 - 创建 .env.example 环境变量示例文件 - 设置 .eslintignore 忽略检查规则 - 配置 .eslintrc.js 代码检查规则 - 添加 .gitignore 文件忽略版本控制 - 设置 .prettierignore 忽略格式化规则 - 新增隐私政策HTML页面文件 - 创建API密钥编辑组件基础结构
This commit is contained in:
266
src/views/system/version/components/version-edit.vue
Normal file
266
src/views/system/version/components/version-edit.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<!-- 角色编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="800"
|
||||
:visible="visible"
|
||||
:confirm-loading="loading"
|
||||
:title="isUpdate ? '修改版本' : '更新版本'"
|
||||
:body-style="{ paddingBottom: '8px' }"
|
||||
@update:visible="updateVisible"
|
||||
@ok="save"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="styleResponsive ? { md: 5, sm: 5, xs: 24 } : { flex: '90px' }"
|
||||
:wrapper-col="
|
||||
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-form-item label="安装包" name="iosDownloadUrl">
|
||||
<a-upload :show-upload-list="false" :customRequest="onUpload">
|
||||
<a-button type="primary" class="ele-btn-icon">
|
||||
<template #icon>
|
||||
<upload-outlined />
|
||||
</template>
|
||||
<span>上传</span>
|
||||
</a-button>
|
||||
</a-upload>
|
||||
</a-form-item>
|
||||
<a-form-item label="版本名" name="versionName">
|
||||
<a-input placeholder="1.0.0" v-model:value="form.versionName" />
|
||||
</a-form-item>
|
||||
<a-form-item label="版本号" name="versionCode">
|
||||
<a-input placeholder="100" v-model:value="form.versionCode" />
|
||||
</a-form-item>
|
||||
<a-form-item label="更新日志" name="updateInfo">
|
||||
<!-- 编辑器 -->
|
||||
<byte-md-editor
|
||||
v-model:value="content"
|
||||
placeholder="请描述您的问题,支持图片粘贴"
|
||||
:locale="zh_Hans"
|
||||
:plugins="plugins"
|
||||
mode="tab"
|
||||
height="300px"
|
||||
maxLength="500"
|
||||
:editorConfig="{ lineNumbers: true }"
|
||||
@paste="onPaste"
|
||||
/>
|
||||
<!-- <a-textarea-->
|
||||
<!-- :rows="4"-->
|
||||
<!-- :maxlength="200"-->
|
||||
<!-- placeholder="请输入更新日志"-->
|
||||
<!-- v-model:value="form.updateInfo"-->
|
||||
<!-- />-->
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import useFormData from '@/utils/use-form-data';
|
||||
import { UploadOutlined } from '@ant-design/icons-vue';
|
||||
import { messageLoading } from 'ele-admin-pro';
|
||||
import { Version } from '@/api/system/version/model';
|
||||
import { ItemType } from "ele-admin-pro/es/ele-image-upload/types";
|
||||
import { addVersion, updateVersion } from '@/api/system/version';
|
||||
// 中文语言文件
|
||||
import zh_Hans from 'bytemd/locales/zh_Hans.json';
|
||||
import zh_HansGfm from "@bytemd/plugin-gfm/locales/zh_Hans.json";
|
||||
import highlight from "@bytemd/plugin-highlight";
|
||||
import gfm from "@bytemd/plugin-gfm";
|
||||
import { uploadOss } from "@/api/system/file";
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const { styleResponsive } = storeToRefs(themeStore);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: Version | null;
|
||||
}>();
|
||||
|
||||
//
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
|
||||
const content = ref('');
|
||||
|
||||
const files = ref<ItemType[]>([]);
|
||||
|
||||
// 表单数据
|
||||
const { form, resetFields, assignFields } = useFormData<Version>({
|
||||
id: undefined,
|
||||
versionName: '',
|
||||
versionCode: '',
|
||||
updateInfo: '',
|
||||
iosDownloadUrl: '',
|
||||
androidDownloadUrl: '',
|
||||
vueDownloadUrl: '',
|
||||
comments: ''
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<Record<string, Rule[]>>({
|
||||
iosDownloadUrl: [
|
||||
{
|
||||
required: true,
|
||||
message: '请上传安装包',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
versionName: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入版本名',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
versionCode: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入版本名',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 插件
|
||||
const plugins = ref([
|
||||
gfm({
|
||||
locale: zh_HansGfm
|
||||
}),
|
||||
highlight()
|
||||
]);
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
if (!formRef.value) {
|
||||
return;
|
||||
}
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
const saveOrUpdate = isUpdate.value ? updateVersion : addVersion;
|
||||
console.log(form);
|
||||
const data = {
|
||||
...form,
|
||||
updateInfo: content.value
|
||||
};
|
||||
saveOrUpdate(data)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
updateVisible(false);
|
||||
emit('done');
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
/* 上传 */
|
||||
const onUpload = ({ file }) => {
|
||||
if (file.size / 1024 / 1024 > 100) {
|
||||
message.error('大小不能超过 100MB');
|
||||
return false;
|
||||
}
|
||||
const hide = messageLoading({
|
||||
content: '上传中..',
|
||||
duration: 0,
|
||||
mask: true
|
||||
});
|
||||
uploadOss(file)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
hide();
|
||||
form.androidDownloadUrl = res.downloadUrl;
|
||||
form.iosDownloadUrl = res.downloadUrl;
|
||||
form.vueDownloadUrl = res.downloadUrl;
|
||||
message.success('上传成功');
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/* 粘贴图片上传服务器并插入编辑器 */
|
||||
const onPaste = (e) => {
|
||||
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
|
||||
let hasFile = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
let file = items[i].getAsFile();
|
||||
const item: ItemType = {
|
||||
file,
|
||||
uid: (file as any).lastModified,
|
||||
name: file.name
|
||||
};
|
||||
uploadOss(<File>item.file)
|
||||
.then((result) => {
|
||||
const addPath = '\n\r';
|
||||
content.value = content.value + addPath
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message);
|
||||
});
|
||||
hasFile = true;
|
||||
}
|
||||
}
|
||||
if (hasFile) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
if(props.data.updateInfo){
|
||||
content.value = props.data.updateInfo;
|
||||
}
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
isUpdate.value = false;
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
formRef.value?.clearValidate();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
208
src/views/system/version/index.vue
Normal file
208
src/views/system/version/index.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="ele-body ele-body-card">
|
||||
<a-card
|
||||
title="软件更新"
|
||||
:bordered="false"
|
||||
:body-style="{ paddingTop: '0px', minHeight: '800px' }"
|
||||
>
|
||||
<template v-if="company.tenantId == 5" #extra>
|
||||
<a @click="openEdit()">上传</a>
|
||||
</template>
|
||||
<a-form
|
||||
:label-col="
|
||||
styleResponsive
|
||||
? { lg: 3, md: 6, sm: 4, xs: 24 }
|
||||
: { flex: '100px' }
|
||||
"
|
||||
:wrapper-col="styleResponsive ? { offset: 1 } : { offset: 1 }"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
<a-form-item label="当前版本">
|
||||
<a-space class="justify">
|
||||
<a-statistic :value="versionName ? versionName : company.versionName" />
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="立即更新">
|
||||
<div class="ele-text-secondary" v-if="versionName == company.versionName">已是最新版本</div>
|
||||
<a-button type="primary" v-else @click="update">立即更新</a-button>
|
||||
</a-form-item>
|
||||
<a-divider style="padding-bottom: 20px" />
|
||||
<a-form-item label="更新日志">
|
||||
<a-timeline>
|
||||
<a-timeline-item v-for="(item,index) in list" :key="index" :color="index == 0 ? 'blue' : 'gray'">
|
||||
<div class="version-name">
|
||||
<span class="title ele-text-heading">{{ item.versionName }}</span>
|
||||
<span class="ele-text-placeholder">{{ toDateString(item.createTime, "YYYY-MM-dd") }}</span>
|
||||
<a-space :size="12">
|
||||
<template v-if="hasRole('superAdmin') || hasRole('admin')">
|
||||
<a @click="download(item)">下载</a>
|
||||
</template>
|
||||
<template v-if="company.tenantId == 5 && (hasRole('superAdmin') || hasRole('admin'))">
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openEdit(item)">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm
|
||||
placement="topRight"
|
||||
title="确定要删除此版本吗?"
|
||||
@confirm="remove(item)"
|
||||
>
|
||||
<a class="ele-text-danger">删除</a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-space>
|
||||
</div>
|
||||
<a-typography-text>
|
||||
<div class="update-info ele-text-secondary" v-html="item.updateInfo"></div>
|
||||
<!-- <byte-md-viewer v-if="item" :value="item.updateInfo" :plugins="plugins" />-->
|
||||
</a-typography-text>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
<versionEdit v-model:visible="showEdit" :data="current" @done="query" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useThemeStore } from "@/store/modules/theme";
|
||||
import { getCompany, updateCompany } from "@/api/system/company";
|
||||
import { assignObject, toDateString } from "ele-admin-pro";
|
||||
import { Company } from "@/api/system/company/model";
|
||||
import { ItemType } from "ele-admin-pro/es/ele-image-upload/types";
|
||||
import { uploadFile } from "@/api/system/file";
|
||||
import { useTenantStore } from "@/store/modules/tenant";
|
||||
import { listVersion, removeVersion } from "@/api/system/version";
|
||||
import { Version } from "@/api/system/version/model";
|
||||
import versionEdit from "./components/version-edit.vue";
|
||||
import { messageLoading } from "ele-admin-pro/es";
|
||||
import { openNew } from "@/utils/common";
|
||||
import { onClone } from "@/utils/plug-uitl";
|
||||
import { hasRole } from "@/utils/permission";
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const { styleResponsive } = storeToRefs(themeStore);
|
||||
const tenantStore = useTenantStore();
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 当前编辑数据
|
||||
const current = ref<Version | null>(null);
|
||||
const list = ref<Version[]>([]);
|
||||
// 当前版本
|
||||
const versionName = ref<string>("");
|
||||
// 登录用户信息
|
||||
const company = computed(() => tenantStore.company ?? {});
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<Company>({
|
||||
companyId: undefined,
|
||||
shortName: "",
|
||||
companyName: "",
|
||||
companyType: undefined,
|
||||
companyLogo: "",
|
||||
domain: "",
|
||||
version: undefined,
|
||||
versionName: "",
|
||||
versionCode: "",
|
||||
createTime: "",
|
||||
updateTime: ""
|
||||
});
|
||||
|
||||
const download = (row?: Version) => {
|
||||
if (row?.vueDownloadUrl) {
|
||||
openNew(row?.vueDownloadUrl);
|
||||
}
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: Version) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 删除单个 */
|
||||
const remove = (row: Version) => {
|
||||
const hide = messageLoading("请求中..", 0);
|
||||
removeVersion(row.id)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
query();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const update = () => {
|
||||
company.value.tenantId = 5;
|
||||
company.value.tenantName = "最新版本";
|
||||
onClone(company.value);
|
||||
};
|
||||
|
||||
|
||||
const onUpload = (d: ItemType) => {
|
||||
const file = d.file;
|
||||
if (file) {
|
||||
if (file.size / 1024 > 100) {
|
||||
message.error("大小不能超过 100k");
|
||||
return;
|
||||
}
|
||||
}
|
||||
uploadFile(<File>d.file)
|
||||
.then((result) => {
|
||||
form.companyLogo = result.url;
|
||||
updateCompany(form).then(res => {
|
||||
message.success("上传成功");
|
||||
});
|
||||
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const query = () => {
|
||||
listVersion({}).then(data => {
|
||||
if (data) {
|
||||
list.value = data;
|
||||
list.value.map((d, i) => {
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
if (i == 0) {
|
||||
versionName.value = `${d.versionName}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
getCompany().then((response) => {
|
||||
assignObject(form, response);
|
||||
});
|
||||
};
|
||||
|
||||
query();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "SystemVersion"
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.justify {
|
||||
display: flex !important;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.update-info {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.version-name {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user