【v3.8.3】前端小改动汇总集合

pull/8786/merge
JEECG 2025-09-14 10:39:48 +08:00
parent d76842ae07
commit 4f46213df6
34 changed files with 466 additions and 64 deletions

View File

@ -1,10 +1,10 @@
JeecgBoot 企业级低代码开发平台
===============
当前最新版本: 3.8.2预计发布时间2025-08-04
当前最新版本: 3.8.3预计发布时间2025-09-22
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://jeecg.com/aboutusIndex)
[![](https://img.shields.io/badge/version-3.8.2-brightgreen.svg)](https://github.com
[![](https://img.shields.io/badge/version-3.8.3-brightgreen.svg)](https://github.com
/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)

View File

@ -32,6 +32,7 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
try {
realName = JSON.parse(realName.replace(/'/g, '"'));
} catch (error) {
console.log("PARSE VITE PROXY ERROR:", error);
realName = '';
}
}

View File

@ -1,5 +1,10 @@
import { defHttp } from '/@/utils/http/axios';
import { getMenuListResultModel } from './model/menuModel';
import { useUserStoreWithOut } from '@/store/modules/user';
import { setAuthCache } from '@/utils/auth';
import { TOKEN_KEY } from '@/enums/cacheEnum';
import { router } from '@/router';
import { PageEnum } from '@/enums/pageEnum';
enum Api {
GetMenuList = '/sys/permission/getUserPermissionByToken',
@ -28,7 +33,21 @@ export const getMenuList = () => {
* @description: 获取后台菜单权限和按钮权限
*/
export function getBackMenuAndPerms() {
return defHttp.get({ url: Api.GetMenuList });
return defHttp.get({ url: Api.GetMenuList }).catch((e) => {
// Token 2025-09-08 scott
if (e && (e.message.includes('timeout') || e.message.includes('401'))) {
const userStore = useUserStoreWithOut();
userStore.setToken('');
setAuthCache(TOKEN_KEY, null);
router.push({
path: PageEnum.BASE_LOGIN,
query: {
//
redirect: router.currentRoute.value.fullPath,
}
});
}
});
}
/**

View File

@ -81,13 +81,12 @@ export function phoneLoginApi(params: LoginParams, mode: ErrorMessageMode = 'mod
export function getUserInfo() {
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, {}).catch((e) => {
// update-begin--author:zyf---date:20220425---for:VUEN-76,
// Token
if (e && (e.message.includes('timeout') || e.message.includes('401'))) {
//
const userStore = useUserStoreWithOut();
userStore.setToken('');
setAuthCache(TOKEN_KEY, null);
// update-begin-author:sunjianlei date:20230306 for:
router.push({
path: PageEnum.BASE_LOGIN,
query: {
@ -95,8 +94,6 @@ export function getUserInfo() {
redirect: router.currentRoute.value.fullPath,
}
});
// update-end-author:sunjianlei date:20230306 for:
}
// update-end--author:zyf---date:20220425---for:VUEN-76,
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -3,6 +3,8 @@
v-bind="attrs_"
v-model:value="state"
:options="getOptions"
show-search
:filter-option="filterOption"
@change="handleChange"
@dropdownVisibleChange="handleFetch"
@popupScroll="handlePopupScroll"
@ -152,7 +154,14 @@
watchEffect(() => {
props.value && handleFetch();
});
/**
* 筛选流程
* @param input
* @param option
*/
const filterOption = (input: string, option: any) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0 || option.label.indexOf(input) >= 0;
};
async function fetch() {
const api = props.api;
if (!api || !isFunction(api)) return;
@ -240,7 +249,7 @@
}
}
// update-end--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange, handlePopupScroll };
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange, handlePopupScroll,filterOption };
},
});
</script>

View File

@ -492,7 +492,6 @@
const showSuffix = !!suffix;
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
return (
<Form.Item
name={field}

View File

@ -15,6 +15,7 @@
@change="onChange"
@search="onSearch"
:tree-checkable="treeCheckAble"
:tagRender="tagRender"
>
<template #[name]="data" v-for="name in slotNamesGroup" :key="name">
<slot :name="name" v-bind="data"></slot>
@ -63,6 +64,10 @@
treeCheckAble: propTypes.bool.def(false),
//update-end---author:wangshuai date: 20230202 for:
hiddenNodeKey: propTypes.string.def(''),
//update-begin---author:wangshuai---date:2025-09-06---for: tag---
//tag
tagRender: propTypes.func,
//update-end---author:wangshuai---date:2025-09-06---for:tag---
});
const attrs = useAttrs();
const { t } = useI18n();

View File

@ -0,0 +1,96 @@
<template>
<div>
<svg
class="svg-company"
v-if="orgCategory && (orgCategory === '1' || orgCategory === '4')"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="256"
height="256"
>
<path
d="M234.9 226.9c0-25.9 25.1-46.9 56-46.9h226.9c30.5 0 55.3 21.1 55.3 46.9v580.9h40V340.2h132.5c25.9 0 46.9 21.1 46.9 46.9v413.5h40V387.2c0-47.9-39-86.9-86.9-86.9H613v-73.4c0-23.7-10.2-45.8-28.7-62.3-17.9-15.9-41.5-24.7-66.6-24.7H290.9c-52.9 0-96 39-96 86.9v580.9h40V226.9zM145.8 841.2h734.9v40H145.8z"
fill="#333333"
p-id="10104"
></path>
<path
d="M286.9 354.1h124.7v40H286.9zM448.1 353.9h63.2v40h-63.2zM286.9 489.1h124.7v40H286.9zM448.1 488.9h63.2v40h-63.2zM286.9 616.6h124.7v40H286.9zM448.1 616.3h63.2v40h-63.2zM638.5 433.1h71v40h-71zM730.2 433h36v40h-36zM638.5 557.9h71v40h-71zM730.2 557.7h36v40h-36zM638.5 684.7h71v40h-71zM730.2 684.5h36v40h-36z"
fill="#333333"
></path>
</svg>
<svg class="svg-depart" v-if="orgCategory === '2'" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="256" height="256">
<path
d="M192 384H64V64h320v320H256v256h128v128h384V512h-128V192h320v320h-128v320H384v128H64v-320h128V384z m128 320H128v192h192v-192z m576-448h-192v192h192V256zM320 128H128v192h192V128z"
p-id="8946"
></path>
</svg>
<svg
class="svg-post"
v-if="orgCategory === '3'"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="11309"
width="256"
height="256"
>
<path
d="M866.346667 89.6H207.573333C167.253333 89.6 134.4 122.453333 134.4 162.773333v146.346667h64V162.773333c0-5.12 4.266667-9.173333 9.173333-9.173333h658.773334c5.12 0 9.173333 4.053333 9.173333 9.173333v699.946667c0 5.12-4.053333 9.173333-9.173333 9.173333H207.573333c-5.12 0-9.173333-4.053333-9.173333-9.173333v-144h-64v144c0 40.32 32.853333 73.173333 73.173333 73.173333h658.773334c40.32 0 73.173333-32.853333 73.173333-73.173333V162.773333c0-40.32-32.853333-73.173333-73.173333-73.173333z"
p-id="11310"
></path>
<path
d="M134.4 428.16h64V597.333333h-64zM120.96 400.64h82.346667c17.706667 0 32-14.293333 32-32s-14.293333-32-32-32H120.96c-17.706667 0-32 14.293333-32 32s14.506667 32 32 32zM233.386667 657.493333c0-17.706667-14.293333-32-32-32H119.04c-17.706667 0-32 14.293333-32 32s14.293333 32 32 32h82.346667c17.706667 0 32-14.293333 32-32zM384.213333 655.146667l146.346667 139.306666c6.186667 5.973333 14.08 8.746667 21.973333 8.746667s15.786667-2.986667 21.973334-8.746667l148.053333-139.306666c8.746667-8.106667 12.16-20.48 8.746667-32l-64.853334-228.053334 39.68-122.666666c3.2-9.813333 1.493333-20.48-4.48-28.586667s-15.573333-13.226667-25.813333-13.226667H428.586667a31.872 31.872 0 0 0-30.293334 41.813334l40.96 126.933333-63.786666 224c-3.2 11.306667 0.213333 23.68 8.746666 31.786667z m168.533334 72.32l-110.506667-105.173334 56.96-199.893333h108.373333l56.96 199.893333-111.786666 105.173334z m78.933333-432.64l-19.413333 60.16h-120.32l-19.413334-60.16h159.146667z"
p-id="11311"
></path>
</svg>
<span :title="title">{{ title }}</span>
</div>
</template>
<script setup lang="ts">
import { defineProps } from 'vue';
const props = defineProps({
orgCategory: String,
title: String,
});
</script>
<style scoped lang="less">
.svg-company {
width: 18px;
height: 18px;
position: relative;
top: 2px;
right: 2px;
}
.svg-depart,
.svg-post {
width: 14px;
height: 16px;
position: relative;
top: 3px;
right: 2px;
}
html[data-theme='light'] {
.svg-post{
path { fill: #333333; }
}
.svg-company{
path { fill: #333333; }
}
.svg-depart{
path { fill: #333333; }
}
}
html[data-theme='dark'] {
.svg-post{
path { fill: #ffffff; }
}
.svg-company{
path { fill: #ffffff; }
}
.svg-depart{
path { fill: #ffffff; }
}
}
</style>

View File

@ -171,6 +171,7 @@
component: (hasCustomApi.value && !props.customApiJInput) ? 'Input' : 'JInput',
},
],
autoSubmitOnEnter: true
};
//
const columns = [

View File

@ -382,6 +382,9 @@
getSize: () => {
return unref(getBindValues).size as SizeType;
},
// update-begin--author:liaozhiyang---date:20250904---forQQYUN-13558erp5
getBindValuesRef: () => getBindValues,
// update-end--author:liaozhiyang---date:20250904---forQQYUN-13558erp5
};
createTableContext({ ...tableAction, wrapRef, getBindValues });

View File

@ -7,12 +7,12 @@
<template v-else>
<Tooltip v-if="action.tooltip" v-bind="getTooltip(action.tooltip)">
<PopConfirmButton v-bind="action">
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" :color="action.iconColor"/>
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
<template v-if="action.label">{{ action.label }}</template>
</PopConfirmButton>
</Tooltip>
<PopConfirmButton v-else v-bind="action">
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" :color="action.iconColor"/>
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
<template v-if="action.label">{{ action.label }}</template>
</PopConfirmButton>
</template>

View File

@ -121,6 +121,7 @@ export interface TableActionType {
getShowPagination: () => boolean;
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
getColumnsRef: () => ComputedRef<BasicColumn[]>;
getBindValuesRef: () => ComputedRef<any>;
}
export interface FetchSetting {

View File

@ -129,7 +129,7 @@
}
function getMyAvatar(){
return userInfo.avatar;
return getFileAccessHttpUrl(userInfo.avatar);
}
//

View File

@ -25,7 +25,7 @@
<upload-chunk ref="uploadRef" :visible="uploadVisible" @select="selectFirstFile"></upload-chunk>
</div>
<UserSelectModal rowKey="username" @register="registerModal" @selected="setValue" :multi="false"></UserSelectModal>
<a-modal v-model:open="visibleEmoji" :footer="null" wrapClassName="emoji-modal" :closable="false" :width="490">
<a-modal v-model:open="visibleEmoji" :footer="null" wrapClassName="emoji-modal" :closable="false" :width="460">
<template #title>
<span></span>
</template>
@ -235,7 +235,7 @@
}
const pickerStyles = {
width: '490px'
width: '460px'
/* height: '350px',
top: '0px',
left: '-75px',

View File

@ -16,10 +16,7 @@ interface ListPageOptions {
//
designScope?: string;
//
tableProps: TableProps & {
// defSort
defSort?: DefSort;
};
tableProps: TableProps;
//
pagination?: boolean;
//
@ -49,11 +46,6 @@ interface IDoRequestOptions {
clearSelection?: boolean;
}
interface DefSort {
column: string;
order: 'asc' | 'desc';
}
/**
* listPage页面公共方法
*
@ -93,17 +85,8 @@ export function useListPage(options: ListPageOptions) {
//update-end-author:taoyan date:20220507 for: erp -
//update-begin-author:liusq date:20230410 for:[/issues/409],
//
const { defSort } = options?.tableProps ?? {};
if (defSort && !paramsForm?.column) {
// 使 defSort
Object.assign(paramsForm, {
column: (defSort as DefSort).column,
order: (defSort as DefSort).order,
});
} else if (!paramsForm?.column) {
// ,使
Object.assign(paramsForm, { column: 'createTime', order: 'desc' });
if(!paramsForm?.column){
Object.assign(paramsForm,{column:'createTime',order:'desc'});
}
//update-begin-author:liusq date:20230410 for: [/issues/409],

View File

@ -1,5 +1,5 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="600px">
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="500px" :bodyStyle="{ padding: '20px 40px 20px 20px'}">
<BasicForm @register="registerForm" />
</BasicModal>
</template>

View File

@ -35,7 +35,7 @@
// components
import { Dropdown, Menu } from 'ant-design-vue';
import { defineComponent, computed, ref, nextTick } from 'vue';
import { defineComponent, computed, ref } from 'vue';
import { SITE_URL } from '/@/settings/siteSetting';

View File

@ -5,6 +5,7 @@ import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { mainOutRoutes } from './mainOut';
import { PageEnum } from '/@/enums/pageEnum';
import { t } from '/@/hooks/web/useI18n';
import { LAYOUT } from '/@/router/constant';
const modules = import.meta.glob('./modules/**/*.ts', { eager: true });

View File

@ -3,7 +3,7 @@ import { merge, random } from 'lodash-es';
import { isArray } from '/@/utils/is';
import { FormSchema } from '/@/components/Form';
import { reactive } from "vue";
import { getTenantId, getToken } from "/@/utils/auth";
import { getTenantId, getToken, getAuthCache, setAuthCache } from "/@/utils/auth";
import { useUserStoreWithOut } from "/@/store/modules/user";
import dayjs from 'dayjs';
import Big from 'big.js';
@ -609,3 +609,28 @@ export function freezeDeep(obj: Recordable | Recordable[]) {
}
return obj
}
/**
* 获取父级名称
*
* @param orgCode 当前部门的code
* @param label 当前默认显示的值
* @param depId depId
* @return 部门名称
*/
export async function getDepartPathNameByOrgCode(orgCode, label, depId){
let key:any = "DEPARTNAME" + depId + orgCode;
let authCache = getAuthCache(key);
if (authCache) {
return authCache;
}
if (orgCode) {
depId = "";
}
let result = await defHttp.get({ url: "/sys/sysDepart/getDepartPathNameByOrgCode", params:{ orgCode: orgCode, depId: depId } }, { isTransformResponse: false });
if (result.success) {
setAuthCache(key,result.result);
return result.result;
}
return label;
}

View File

@ -39,7 +39,7 @@ export default class signMd5Utils {
//update-end---author:wangshuai---date:2024-04-16---for:【QQYUN-9005】发送短信加签---
let requestBody = this.sortAsc(jsonObj);
delete requestBody._t;
console.log('sign requestBody:', requestBody);
// console.log('sign requestBody:', requestBody);
return md5(JSON.stringify(requestBody) + signatureSecret).toUpperCase();
}

View File

@ -58,6 +58,9 @@
</div>
</div>
</template>
<a v-if="noticeFiles.length > 1" :href="downLoadFiles + '?id=' + content.id + '&token=' + getToken()" target="_blank" style="margin: 15px 6px; color: #5ac0fa">
<download-outlined class="item-icon" style="margin-right: 5px" /><span>批量下载所有附件</span>
</a>
</template>
</BasicModal>
</template>
@ -72,15 +75,21 @@
import { getFileAccessHttpUrl } from '@/utils/common/compUtils';
import { useGlobSetting } from '@/hooks/setting';
import { encryptByBase64 } from '@/utils/cipher';
import { getToken } from '@/utils/auth';
const router = useRouter();
const glob = useGlobSetting();
const isUpdate = ref(true);
const content = ref<any>({});
const noticeFiles = ref([]);
/**
* 下载文件路径
*/
const downLoadFiles = `${glob.domainUrl}/sys/annountCement/downLoadFiles`;
const emit = defineEmits(['close', 'register']);
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
isUpdate.value = !!data?.isUpdate;
noticeFiles.value = [];
if (unref(isUpdate)) {
//data.record.msgContent = '<p>2323</p><input onmouseover=alert(1)>xss test';
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702 sql
@ -194,6 +203,24 @@
padding: 0;
}
}
.ant-card-meta-detail {
display: flex !important ;
justify-content: center !important;
align-items: center !important;
flex-direction: column !important;
}
.ant-card-meta-title {
font-size: 22px !important;
color: rgba(51, 51, 51, 0.88);
font-weight: 600;
font-size: 16px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ant-card .ant-card-meta-description {
color: rgba(51, 51, 51, 0.45);
}
`;
frameDoc.head.appendChild(style);
@ -273,8 +300,8 @@
.print-btn {
position: absolute;
top: 20px;
right: 20px;
top: 80px;
right: 40px;
cursor: pointer;
color: #a3a3a5;
z-index: 999;

View File

@ -78,4 +78,4 @@ export const deleteThirdAppConfig = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteThirdAppConfig, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
};

View File

@ -335,7 +335,7 @@
searchParams.realname = options[0].label;
}
}
function openSelectPerson(){
openModal(true, {})
}

View File

@ -161,7 +161,7 @@ export function useSysMessage(setLocaleText) {
}
}
return '去处理'
}else{
} else {
return '查看详情'
}
}

View File

@ -28,6 +28,9 @@
</div>
</div>
</template>
<a v-if="noticeFiles.length > 1" :href="downLoadFiles + '?id=' + noticeId + '&token=' + getToken()" target="_blank" style="margin: 15px 6px;color: #5ac0fa;">
<download-outlined class="item-icon" style="margin-right: 5px" /><span>批量下载所有附件</span>
</a>
</template>
</BasicModal>
</template>
@ -40,16 +43,25 @@
import { DownloadOutlined, EyeOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
import { encryptByBase64 } from '@/utils/cipher';
import { useGlobSetting } from '@/hooks/setting';
import { getToken } from "@/utils/auth";
const glob = useGlobSetting();
// props
defineProps({
frameSrc: propTypes.string.def(''),
});
/**
* 下载文件路径
*/
const downLoadFiles = `${glob.domainUrl}/sys/annountCement/downLoadFiles`;
//
const noticeFiles = ref([]);
//ID
const noticeId = ref('');
//
const [registerModal] = useModalInner((data) => {
noticeFiles.value = [];
noticeId.value = data.record.id;
if (data.record?.files && data.record?.files.length > 0) {
noticeFiles.value = data.record.files.split(',').map((item) => {
return {
@ -96,8 +108,8 @@
<style scoped lang="less">
.print-btn {
position: absolute;
top: 20px;
right: 20px;
top: 80px;
right: 40px;
cursor: pointer;
color: #a3a3a5;
z-index: 999;

View File

@ -52,6 +52,13 @@
...data.record,
});
record.value = data.record;
} else {
// update-begin--author:liaozhiyang---date:20250807---forJHHB-128
//
await setFieldsValue({
...data.record,
});
// update-end--author:liaozhiyang---date:20250807---forJHHB-128
}
});
//

View File

@ -29,7 +29,7 @@
</div>
</template>
<script lang="ts" name="system-notice" setup>
import { ref } from 'vue';
import { ref, onMounted } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import NoticeModal from './NoticeModal.vue';
@ -40,6 +40,9 @@
import { columns, searchFormSchema } from './notice.data';
import { getList, deleteNotice, batchDeleteNotice,editIzTop, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api';
import { useListPage } from '/@/hooks/system/useListPage';
import { useAppStore } from '/@/store/modules/app';
const appStore = useAppStore();
const glob = useGlobSetting();
const [registerModal, { openModal }] = useModal();
const [register, { openModal: openDetail }] = useModal();
@ -71,9 +74,10 @@
/**
* 新增事件
*/
function handleAdd() {
function handleAdd(record = {}) {
openModal(true, {
isUpdate: false,
record,
});
}
@ -192,4 +196,15 @@
},
];
}
onMounted(() => {
// update-begin--author:liaozhiyang---date:20250807---forJHHB-128
const params = appStore.getMessageHrefParams;
if (params?.add) {
delete params.add;
handleAdd(params);
appStore.setMessageHrefParams('');
}
// update-begin--author:liaozhiyang---date:20250807---forJHHB-128
});
</script>

View File

@ -12,9 +12,7 @@ enum Api {
releaseData = '/sys/annountCement/doReleaseData',
reovkeData = '/sys/annountCement/doReovkeData',
editIzTop = '/sys/annountCement/editIzTop',
addVisitsNum = '/sys/annountCement/addVisitsNumber',
tempList = '/sys/message/sysMessageTemplate/list',
}
@ -88,12 +86,6 @@ export const addVisitsNum = (params) => defHttp.get({ url: Api.addVisitsNum, par
* @param id
*/
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
/**
* 发起流程
* import { startProcess } from '/@/api/common/api';
* @param params
*/
export const startProcess = (params) => defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
/**
* 查询模板列表
* @param params

View File

@ -3,7 +3,10 @@
<template #title>
角色权限配置
<a-dropdown>
<Icon icon="ant-design:more-outlined" class="more-icon" />
<a-button class="more-icon">
更多操作
<Icon icon="ant-design:down-outlined" size="14px" style="position: relative;top: 1px;right: 5px"></Icon>
</a-button>
<template #overlay>
<a-menu @click="treeMenuClick">
<a-menu-item key="checkAll">选择全部</a-menu-item>
@ -294,9 +297,9 @@
border-bottom: 1px solid #f0f0f0;
}
.more-icon {
font-size: 20px !important;
/* font-size: 20px !important;
color: black;
display: inline-flex;
display: inline-flex;*/
float: right;
margin-right: 2px;
cursor: pointer;

View File

@ -57,7 +57,14 @@ export const searchUserFormSchema: FormSchema[] = [
field: 'username',
label: '用户账号',
component: 'Input',
colProps: { span: 12 },
colProps: { span: 8 },
labelWidth: 74,
},
{
field: 'realname',
label: '用户名称',
component: 'Input',
colProps: { span: 8 },
labelWidth: 74,
},
];

View File

@ -10,7 +10,7 @@
@change="updateAvatar"
width="80"
/>
<div class="account-right">
<div class="account-right border-bottom">
<div v-if="!isEdit">
<span class="font-size-17 account-name">{{ userInfo.realname }}</span>
<a-tooltip content="编辑姓名">
@ -27,7 +27,7 @@
</div>
</div>
</div>
<div class="account-data">
<div class="account-data border-bottom">
<!-- 详细资料 -->
<div class="account-detail">
<div class="font-size-15 font-bold font-color-gray" style="margin-bottom: 16px">详细资料</div>
@ -61,6 +61,47 @@
</div>
</div>
</div>
<div class="account-data">
<!-- 个性签名 -->
<div class="account-detail">
<div class="font-size-15 font-bold font-color-gray" style="margin-bottom: 16px">个性签名</div>
<div class="font-size-13 flex">
<span class="gray-75 item-label">签名</span>
<a-upload
accept="jpg,jpeg,png"
:max-count="1"
:multiple="false"
name = "file"
:headers="uploadHeader"
:action="uploadUrl"
v-model:fileList="uploadFileList"
@beforeUpload="beforeUpload"
@change="handleChange"
list-type="picture-card"
@preview="handlePreview"
>
<div v-if="uploadVisible">
<UploadOutlined></UploadOutlined>
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-modal :width="500" :open="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
<div style="font-size: 12px;color:#93a6aa" class="margin-bottom-10">
<p>建议上传尺寸为200*80大小不超过1M且格式为png或jpeg的图片</p>
<p>生成签名方法一手写扫描进行上传</p>
<p>生成签名方法二使用在线转换生成后进行上传
<a href="http://www.diyiziti.com/qianming" target="_blank">http://www.diyiziti.com/qianming</a>
</p>
</div>
<div class="margin-bottom-10 font-size-13 flex" style="margin-top: 10px">
<span class="gray-75 item-label">开启状态</span>
<a-switch v-model:checked="userInfo.signEnable" :checkedValue="1" :unCheckedValue="0" @change="handleEnableSignChange"></a-switch>
</div>
</div>
</div>
</div>
<UserAccountModal @register="registerModal" @success="getUserDetail"></UserAccountModal>
</template>
@ -73,7 +114,7 @@ import headerImg from '/@/assets/images/header.jpg';
import { defHttp } from '/@/utils/http/axios';
import { useUserStore } from '/@/store/modules/user';
import { uploadImg } from '/@/api/sys/upload';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { getFileAccessHttpUrl, getRandom } from '/@/utils/common/compUtils';
import dayjs from 'dayjs';
import { ajaxGetDictItems, getDictItemsByCode, initDictOptions } from '/@/utils/dict';
import { userEdit, getUserData, queryNameByCodes } from './UserSetting.api';
@ -81,6 +122,10 @@ import UserAccountModal from './commponents/UserAccountModal.vue';
import { useModal } from '/@/components/Modal';
import { cloneDeep } from 'lodash-es';
import { useDesign } from '/@/hooks/web/useDesign';
import { getToken } from "@/utils/auth";
import { uploadUrl } from "@/api/common/api";
import { UploadOutlined } from "@ant-design/icons-vue";
//TODO
const sexOption = getDictItemsByCode("sex") || [{text:'男',value:'1'},{text:'女',value:'2'}];
const { createMessage } = useMessage();
@ -97,6 +142,26 @@ const [registerModal, { openModal }] = useModal();
const avatar = computed(() => {
return getFileAccessHttpUrl(userInfo.value.avatar) || headerImg;
});
//headers
const uploadHeader = computed(() => {
let headers = {};
headers['X-Access-Token'] = getToken();
return headers;
});
const { createMessage: $message } = useMessage();
//
const uploadFileList = ref<any>([]);
//
const uploadVisible = computed(() => {
if(!uploadFileList){
return true;
}
return uploadFileList.value.length < 1;
});
//
const previewVisible = ref<boolean>(false);
//
const previewImage = ref<string>('');
/**
* 更新用户头像
@ -183,6 +248,7 @@ function openEditModal() {
* 获取用户信息
*/
function getUserDetail() {
uploadFileList.value = [];
getUserData().then((async res => {
if (res.success) {
if (res.result) {
@ -190,6 +256,20 @@ function getUserDetail() {
res.result.birthday = getBirthDay(res.result.birthday);
res.result.createTimeText = getDiffDay(res.result.createTime);
userInfo.value = res.result;
if(userInfo.value.sign){
let sign = userInfo.value.sign;
let url = getFileAccessHttpUrl(sign);
uploadFileList.value.push({
uid: getRandom(10),
name: getFileName(sign),
status: 'done',
url: url,
response: {
status: 'history',
message: sign,
},
})
}
} else {
userInfo.value = {};
}
@ -211,6 +291,112 @@ function getDiffDay(date) {
totalDays = Math.floor(diffDate / (1000 * 3600 * 24)) //
return totalDays+" 天";
}
/**
* 上传图片之前进行验证
*
* @param file
*/
function beforeUpload({ file }) {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/jpg";
if (!isJpgOrPng) {
$message.error("上传文件格式只能是jpg/png");
return false;
}
const isLimit = file.size / 1024 / 1024 < 1;
if (!isLimit) {
$message.error("上传图片大小不能超过 1MB!");
return false;
}
return true;
}
/**
* 上传成功事件
*/
function handleChange({ file, fileList }) {
if (file.status === 'error') {
createMessage.error(`${file.name} 上传失败.`);
}
if (file.status === 'done' && file.response.success === false) {
const failIndex = uploadFileList.value.findIndex((item) => item.uid === file.uid);
if (failIndex != -1) {
uploadFileList.value.splice(failIndex, 1);
}
createMessage.warning(file.response.message);
return;
}
if (file.status != 'uploading') {
fileList.forEach((file) => {
if (file.status === 'done') {
//
uploadSuccess(file.response.message);
}
});
if (file.status === 'removed') {
handleDelete();
}
}
}
/**
* 移除
*/
function handleDelete() {
updateUser({ sign: "", id: userInfo.value.id },"删除个性签名成功")
}
/**
* 上传成功事件
* @param url
*/
function uploadSuccess(url) {
updateUser({ sign: url, id: userInfo.value.id },"上传个性签名成功")
}
function updateUser(params,message) {
userEdit(params).then((res) => {
if(res.success){
createMessage.success(message);
}
});
}
/**
* 图片预览
* @param file
*/
function handlePreview(file) {
previewImage.value = file.url || file.thumbUrl;
previewVisible.value = true;
}
/**
* 获取文件名
* @param path
*/
function getFileName(path) {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g');
path = path.replace(reg, '/');
}
return path.substring(path.lastIndexOf('/') + 1);
}
/**
* 图片预览关闭
*/
function handleCancel() {
previewVisible.value = false;
}
/**
* 个性签名开启状态更新
*/
function handleEnableSignChange() {
updateUser({ signEnable: userInfo.value.signEnable, id: userInfo.value.id },"修改成功")
}
onMounted(async () => {
getUserDetail();
});
@ -347,6 +533,19 @@ onMounted(async () => {
.font-size-13 {
font-size: 13px;
}
.ant-upload-select,.ant-upload-list-item-container{
width: 200px !important;
height: 80px !important;
}
.ant-upload-list-item-thumbnail .ant-upload-list-item-image {
object-fit: cover !important;
}
p{
margin-bottom: 5px;
}
.border-bottom{
border-bottom: 1px solid @border-color-base;
}
}
// update-end-author:liusq date:20230625 for: [issues/563]
</style>

View File

@ -43,7 +43,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
// ----- [end] JEECG -----
console.log('[init] Start Port: ', VITE_PORT);
console.log('[init] Vite Proxy Config: ', VITE_PROXY);
console.debug('[init] Vite Proxy Config: ', VITE_PROXY);
return {