Merge branch 'abp' of https://gitee.com/ccnetcore/Yi into abp

This commit is contained in:
橙子
2024-01-02 23:35:34 +08:00
11 changed files with 435 additions and 260 deletions

View File

@@ -0,0 +1,11 @@
import request from "@/config/axios/service";
/**
* 获取图标列表
*/
export function getIconList() {
return request({
url: `/setting/icon`,
method: "get",
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -1,190 +1,194 @@
// @import './variables.module.scss';
// @import './mixin.scss';
// @import './transition.scss';
// @import './element-ui.scss';
// @import './sidebar.scss';
// @import './btn.scss';
// @import './ruoyi.scss';
// body {
// height: 100%;
// margin: 0;
// -moz-osx-font-smoothing: grayscale;
// -webkit-font-smoothing: antialiased;
// text-rendering: optimizeLegibility;
// font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
// }
// label {
// font-weight: 700;
// }
// html {
// height: 100%;
// box-sizing: border-box;
// }
// #app {
// height: 100%;
// }
// *,
// *:before,
// *:after {
// box-sizing: inherit;
// }
// .no-padding {
// padding: 0px !important;
// }
// .padding-content {
// padding: 4px 0;
// }
// a:focus,
// a:active {
// outline: none;
// }
// a,
// a:focus,
// a:hover {
// cursor: pointer;
// color: inherit;
// text-decoration: none;
// }
// div:focus {
// outline: none;
// }
// .fr {
// float: right;
// }
// .fl {
// float: left;
// }
// .pr-5 {
// padding-right: 5px;
// }
// .pl-5 {
// padding-left: 5px;
// }
// .block {
// display: block;
// }
// .pointer {
// cursor: pointer;
// }
// .inlineBlock {
// display: block;
// }
// .clearfix {
// &:after {
// visibility: hidden;
// display: block;
// font-size: 0;
// content: " ";
// clear: both;
// height: 0;
// }
// }
// aside {
// background: #eef1f6;
// padding: 8px 24px;
// margin-bottom: 20px;
// border-radius: 2px;
// display: block;
// line-height: 32px;
// font-size: 16px;
// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
// color: #2c3e50;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// a {
// color: #337ab7;
// cursor: pointer;
// &:hover {
// color: rgb(32, 160, 255);
// }
// }
// }
// .components-container {
// margin: 30px 50px;
// position: relative;
// }
// .pagination-container {
// margin-top: 30px;
// }
.text-center {
text-align: center
/**
* Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
* http://cssreset.com
* 全局初始化样式
*/
html,
body,
div,
span,
applet,
object,
iframe,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video,
input {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font-weight: normal;
vertical-align: baseline;
outline: none;
}
// .sub-navbar {
// height: 50px;
// line-height: 50px;
// position: relative;
// width: 100%;
// text-align: right;
// padding-right: 20px;
// transition: 600ms ease position;
// background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
body {
/* px-to-viewport-ignore-next */
min-width: 1024px; /* px-to-viewport-ignore */
}
html {
/* px-to-viewport-ignore-next */
min-width: 1024px; /* px-to-viewport-ignore */
}
// .subtitle {
// font-size: 20px;
// color: #fff;
// }
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
menu,
nav,
section {
display: block;
}
// &.draft {
// background: #d0d0d0;
// }
blockquote,
q {
quotes: none;
}
// &.deleted {
// background: #d0d0d0;
// }
// }
blockquote::before,
blockquote::after,
q::before,
q::after {
content: none;
}
// .link-type,
// .link-type:focus {
// color: #337ab7;
// cursor: pointer;
table {
border-collapse: collapse;
border-spacing: 0;
}
// &:hover {
// color: rgb(32, 160, 255);
// }
// }
/* custom */
li {
list-style: none;
}
// .filter-container {
// padding-bottom: 10px;
button {
outline: none;
cursor: pointer;
background-color: transparent;
border-style: none;
}
// .filter-item {
// display: inline-block;
// vertical-align: middle;
// margin-bottom: 10px;
// }
// }
.el-textarea__inner::placeholder {
color: #999 !important;
}
// //refine vue-multiselect plugin
// .multiselect {
// line-height: 16px;
// }
.el-input__inner::placeholder {
color: #999 !important;
}
// .multiselect--active {
// z-index: 1000 !important;
// }
input::-webkit-input-placeholder {
color: #999 !important;
}
.el-input__inner::-webkit-input-placeholder {
color: #999 !important;
}
input::placeholder {
color: #999 !important;
}
textarea::placeholder {
color: #999 !important;
}
* {
box-sizing: border-box;
}
html,
body,
#app {
width: 100%;
height: 100%;
font-family: Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif,
Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbo;
}
/* //滚动条样式 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
border-radius: 10px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #ccc;
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(249, 222, 222, 0.6);
}

View File

@@ -117,17 +117,17 @@ const Init = () => {
const statusTypeList = [
{
label: "正常",
value: 0,
value: "Normal",
type: "success",
},
{
label: "危险",
value: 1,
value: "Dangerous",
type: "warning",
},
{
label: "已禁止",
value: 2,
value: "Ban",
type: "danger",
},
];

View File

@@ -1,38 +1,59 @@
<template>
<div class="botton-div">
<a><el-icon><UserFilled /></el-icon>站长{{configStore.author}}</a>
<a><el-icon><Search /></el-icon>{{configStore.bottom}}</a>
<a><el-icon><View /></el-icon>关于本站</a>
<a><el-icon><Message /></el-icon>建议反馈</a>
<p></p>
<a ><el-icon><Position /></el-icon>{{configStore.icp}}</a>
</div>
<div class="botton-div">
<a
><el-icon><UserFilled /></el-icon>站长{{ configStore.author }}</a
>
<a
><el-icon><Search /></el-icon>{{ configStore.bottom }}</a
>
<a
><el-icon><View /></el-icon>关于本站</a
>
<a @click="handleContact"
><el-icon><Link /></el-icon>联系我们</a
>
<a
><el-icon><Message /></el-icon>建议反馈</a
>
<p></p>
<a
><el-icon><Position /></el-icon>{{ configStore.icp }}</a
>
</div>
</template>
<script setup>
import useConfigStore from "@/stores/config";
const configStore= useConfigStore();
import { useRouter } from "vue-router";
const router = useRouter();
const configStore = useConfigStore();
// 联系我们跳转对应页面
const handleContact = () => {
router.push("/contact");
};
</script>
<style scoped>
.el-icon
{margin: 0 0.2rem;}
a{
margin-right: 2rem;
line-height: 1.8rem;
.el-icon {
margin: 0 0.2rem;
}
a {
margin-right: 2rem;
line-height: 1.8rem;
}
a:hover {
color: #40a9ff;
cursor:pointer;
color: #40a9ff;
cursor: pointer;
}
.botton-div
{
background: transparent;
color: rgba(0,0,0,.45);
font-size: 14px;
display: flex;
flex-wrap: wrap;
height: auto;
width: auto;
justify-content: center;
margin: 0.5rem auto;
.botton-div {
background: transparent;
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
display: flex;
flex-wrap: wrap;
height: auto;
width: auto;
justify-content: center;
margin: 0.5rem auto;
}
</style>
</style>

View File

@@ -63,6 +63,11 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="author" @click="handleGitClick">
<el-tooltip effect="dark" content="在gitee找到我们" placement="bottom">
<img src="@/assets/common/icons/gitee.png" alt="" />
</el-tooltip>
</div>
</div>
</div>
</template>
@@ -119,19 +124,33 @@ const search = () => {
};
const isLogin = getToken("AccessToken") ? true : false;
const handleGitClick = () => {
window.open("https://gitee.com/ccnetcore/Yi");
};
</script>
<style scoped lang="scss">
.header {
padding: 0 100px;
width: 1300px;
display: flex;
align-items: center;
justify-content: space-between;
}
.user {
display: flex;
align-items: center;
.author {
cursor: pointer;
width: 25px;
height: 25px;
margin-left: 20px;
img {
width: 100%;
height: 100%;
}
}
.el-dropdown-link {
cursor: pointer;
display: flex;

View File

@@ -1,6 +1,6 @@
<template>
<div class="common-layout">
<el-container>
<el-container class="common-container">
<el-header
class="common-header"
ref="header"
@@ -46,6 +46,10 @@ const handleScroll = () => {
width: 100%;
height: 100%;
}
&-container {
width: 100%;
height: 100%;
}
&-header {
width: 100%;
background-color: #fff;

View File

@@ -47,17 +47,17 @@ const props = defineProps({
const statusTypeList = [
{
label: "正常",
value: 0,
value: "Normal",
type: "success",
},
{
label: "危险",
value: 1,
value: "Dangerous",
type: "warning",
},
{
label: "已禁止",
value: 2,
value: "Ban",
type: "danger",
},
];

View File

@@ -45,17 +45,17 @@ const props = defineProps({
const statusTypeList = [
{
label: "正常",
value: 0,
value: "Normal",
type: "success",
},
{
label: "危险",
value: 1,
value: "Dangerous",
type: "warning",
},
{
label: "已禁止",
value: 2,
value: "Ban",
type: "danger",
},
];

View File

@@ -126,4 +126,9 @@ onMounted(() => {
.app-container {
padding: 20px;
}
.text-center {
display: flex;
justify-content: center;
margin-bottom: 10px;
}
</style>

View File

@@ -1,12 +1,28 @@
<template>
<div class="user-info-head" @click="editCropper()"><img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
<div class="user-info-head" @click="editCropper()">
<img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
</div>
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
<el-dialog
:title="title"
v-model="open"
width="800px"
append-to-body
@opened="modalOpened"
@close="closeDialog"
>
<el-row>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth" :autoCropHeight="options.autoCropHeight" :fixedBox="options.fixedBox"
@realTime="realTime" v-if="visible" />
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
@realTime="realTime"
v-if="visible"
/>
</el-col>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div class="avatar-upload-preview">
@@ -16,16 +32,28 @@
</el-row>
<br />
<el-row>
<el-col :lg="2" :md="2">
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-upload
action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-button>
选择
本地选择
<el-icon class="el-icon--right">
<Upload />
</el-icon>
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 3 }" :md="2">
<el-button @click="handleSelectOnline"
>在线选择<el-icon class="el-icon--right"> <Upload /> </el-icon>
</el-button>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button icon="Plus" @click="changeScale(1)"></el-button>
</el-col>
@@ -38,22 +66,49 @@
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-col :lg="{ span: 2, offset: 8 }" :md="2">
<el-button type="primary" @click="uploadImg()">上传</el-button>
</el-col>
</el-row>
</el-col></el-row
>
</el-dialog>
<!-- 选择已有弹窗 -->
<el-dialog
v-model="isOnlineVisible"
title="在线选择"
append-to-body
width="800px"
>
<div class="imageList">
<template v-for="(item, index) in iconList">
<el-image
style="width: 100px; height: 100px"
:src="item"
:fit="fit"
:class="{ selected: index === selectedImageIndex, imageBox: true }"
@click="selectImage(index)"
/>
</template>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="isOnlineVisible = false">取消</el-button>
<el-button type="primary" @click="confirmImage"> 确认 </el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import "vue-cropper/dist/index.css";
import { ref, reactive, onMounted } from "vue";
import { VueCropper } from "vue-cropper";
import { upload } from "@/apis/fileApi";
import { updateUserIcon } from "@/apis/userApi";
import useUserStore from '@/stores/user'
import { ref, reactive } from "vue";
import { getIconList } from "@/apis/settingApi";
import useUserStore from "@/stores/user";
import axios from "axios";
const userStore = useUserStore()
const userStore = useUserStore();
const cropper = ref(null);
@@ -68,79 +123,125 @@ const options = reactive({
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
previews: {} //预览数据
previews: {}, //预览数据
});
/** 编辑头像 */
function editCropper() {
open.value = true;
};
}
/** 打开弹出层结束时的回调 */
function modalOpened() {
visible.value = true;
};
}
/** 覆盖默认上传行为 */
function requestUpload() {
};
function requestUpload() {}
/** 向左旋转 */
function rotateLeft() {
cropper.value.rotateLeft();
};
}
/** 向右旋转 */
function rotateRight() {
cropper.value.rotateRight();
};
}
/** 图片缩放 */
function changeScale(num) {
num = num || 1;
cropper.value.changeScale(num);
};
}
/** 上传预处理 */
function beforeUpload(file) {
if (file.type.indexOf("image/") == -1) {
ElMessage.error("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。")
ElMessage.error("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
} else {
console.log(file, "file");
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
options.img = reader.result;
};
}
};
}
/** 上传图片 */
async function uploadImg() {
await cropper.value.getCropBlob(async data => {
await cropper.value.getCropBlob(async (data) => {
let formData = new FormData();
formData.append("file", data);
const response = await upload(formData)
const response = await upload(formData);
open.value = false;
options.img = import.meta.env.VITE_APP_BASEAPI + "/file/" + response.data[0].id;
options.img =
import.meta.env.VITE_APP_BASEAPI + "/file/" + response.data[0].id;
userStore.icon = options.img;
const iconResponse= await updateUserIcon(response.data[0].id);
if(iconResponse.status==200)
{
ElMessage({
type: "success",
message: "头像更新成功",
});
}
const iconResponse = await updateUserIcon(response.data[0].id);
if (iconResponse.status == 200) {
ElMessage({
type: "success",
message: "头像更新成功",
});
}
});
};
}
/** 实时预览 */
function realTime(data) {
options.previews = data;
};
}
/** 关闭窗口 */
function closeDialog() {
options.img = userStore.icon;
options.visible = false;
}
// 在线选择相关逻辑
const saveOnlineImage = async (imageUrl) => {
try {
// 发起网络请求下载在线图片
const response = await axios.get(imageUrl, {
responseType: "blob", // 设置响应类型为blob
});
// 创建blob对象
const blob = new Blob([response.data], {
type: response.headers["content-type"],
});
// 创建File对象设置文件名为当前时间戳
const file = new File([blob], `${Date.now()}.jpg`, {
type: response.headers["content-type"],
});
// 可以将file对象传递给其他处理逻辑或进行文件上传操作
return file;
} catch (error) {
console.error("下载图片失败:", error);
}
};
const iconList = ref([]);
const isOnlineVisible = ref(false);
const handleSelectOnline = () => {
isOnlineVisible.value = true;
};
const selectedImageIndex = ref(null);
const selectImage = (index) => {
selectedImageIndex.value = index;
};
const confirmImage = async () => {
if (selectedImageIndex !== null) {
// 在预览区域中显示选择的图片
const selectedImage = iconList.value[selectedImageIndex.value];
const file = await saveOnlineImage(selectedImage);
beforeUpload(file);
}
selectedImageIndex.value = null;
isOnlineVisible.value = false;
};
onMounted(async () => {
const { data: iconListData } = await getIconList();
iconList.value = iconListData.map(
(item) => import.meta.env.VITE_APP_BASEAPI + "/" + item
);
});
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.user-info-head {
position: relative;
display: inline-block;
@@ -149,6 +250,7 @@ function closeDialog() {
.user-info-head:hover:after {
content: "+";
text-align: center;
position: absolute;
left: 0;
right: 0;
@@ -184,4 +286,13 @@ function closeDialog() {
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
</style>
/* 添加选中图片的边框样式 */
.imageBox {
margin: 10px;
}
.selected {
padding: 5px;
border: 2px solid #40a9ff;
}
</style>