8月10日的bug的修改

This commit is contained in:
2025-08-10 20:15:45 +08:00
parent d6f0ba4e6f
commit da9feb26c6
26 changed files with 743 additions and 112 deletions

View File

@ -1,4 +1,5 @@
<template>
<div class="sidebar-container">
<a-menu
v-model:selectedKeys="selectedKeys"
mode="inline"
@ -32,16 +33,16 @@
<!-- <a-menu-item key="/project">接单管理</a-menu-item>-->
<!-- </a-sub-menu>-->
<a-sub-menu>
<template #title>
<span>
<CommentOutlined />
<span>结算管理</span>
</span>
</template>
<a-menu-item key="/applicationRecord">推广码申请记录</a-menu-item>
<a-menu-item key="/withdrawalApplicationRecord">提现申请记录</a-menu-item>
</a-sub-menu>
<!-- <a-sub-menu>-->
<!-- <template #title>-->
<!-- <span>-->
<!-- <CommentOutlined />-->
<!-- <span>结算管理</span>-->
<!-- </span>-->
<!-- </template>-->
<!-- <a-menu-item key="/applicationRecord">推广码申请记录</a-menu-item>-->
<!-- <a-menu-item key="/withdrawalApplicationRecord">提现申请记录</a-menu-item>-->
<!-- </a-sub-menu>-->
<a-sub-menu>
<template #title>
<span>
@ -74,12 +75,19 @@
<a-menu-item key="/employeePerformanceRanking">员工绩效排行</a-menu-item>
</a-sub-menu>
<a-menu-item key="/employeeApplication">
<CommentOutlined />
<span>员工申请管理</span>
</a-menu-item>
</a-menu>
<a-sub-menu>
<template #title>
<span>
<FieldTimeOutlined />
<span>申请管理</span>
</span>
</template>
<a-menu-item key="/employeeApplication">员工申请管理</a-menu-item>
<a-menu-item key="/applicationInstructions">员工申请须知</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</template>
<script setup lang="ts">
@ -109,6 +117,29 @@ const handleClick = (item: any) => {
</script>
<style scoped>
.sidebar-container {
height: 100vh;
overflow-y: auto;
background-color: #ffe7ba;
}
/* 自定义滚动条样式 */
.sidebar-container::-webkit-scrollbar {
width: 6px;
}
.sidebar-container::-webkit-scrollbar-track {
background: transparent;
}
.sidebar-container::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
.sidebar-container::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.2);
}
:deep(.ant-menu-item),
:deep(.ant-menu-submenu-title) {

View File

@ -177,6 +177,11 @@ export const routes = [
name:'员工绩效排行',
component: ()=> import("../view/performance/employeePerformanceRanking.vue")
},
{
path:'/applicationInstructions',
name:'员工申请须知',
component: ()=> import("../view/employeeApplication/applicationInstructions.vue")
},
]
},
]

View File

@ -2,7 +2,7 @@
<div id="login">
<form>
<div class="box" @submit.prevent>
<h2>欢迎登录青橙校园管理端</h2>
<h2>欢迎登录丁香花校园管理端</h2>
<div class="input-box">
<input type="text" placeholder="账号" v-model="userAccount"/>

View File

@ -741,7 +741,7 @@ const handlePriceInput = (value: number, field: keyof CourseDetail) => {
border-radius: 0.75rem;
overflow: hidden;
transition: all 0.3s ease;
max-height: 500px;
max-height: 2000px;
flex-grow: 1;
padding: 10px;
background: white;

View File

@ -504,4 +504,10 @@ const showDetails = (id: string) => {
background-color: #ff4d4f !important;
border-color: #ff4d4f !important;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>

View File

@ -82,6 +82,7 @@
v-if="record.orderStatus === '交易成功'"
size="small"
primary
@click="showRefundConfirm(record)"
>
退款
</a-button>
@ -94,9 +95,48 @@
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import myAxios from "../../api/myAxios.ts";
import { message} from "ant-design-vue";
import { message,Modal} from "ant-design-vue";
import {downLoadImage} from "../../api/ImageUrl.ts";
const handleRefund = async (orderId: number) => {
loading.value = true;
try {
const storedToken = localStorage.getItem('token');
if (!storedToken) throw new Error('未找到登录信息');
const res: any = await myAxios.post(
"/courseOrder/refund",
{ id: orderId },
{ headers: { Authorization: storedToken } }
);
if (res.code === 1 && res.data === true) {
message.success('退款成功');
// 刷新订单列表
await getOrderList();
} else {
message.error(res.message || '退款失败');
}
} catch (error) {
console.error("退款失败:", error);
message.error('退款操作失败');
} finally {
loading.value = false;
}
};
// 显示退款确认弹窗
const showRefundConfirm = (record: Order) => {
Modal.confirm({
title: '确认退款',
content: `确定要对订单 ${record.orderNumber} 执行退款操作吗?`,
okText: '确认退款',
cancelText: '取消',
centered: true,
onOk() {
return handleRefund(record.id);
}
});
};
const loading = ref(false);
const selectedRowKeys = ref<number[]>([]); // 存储选中的行ID
@ -109,7 +149,7 @@ const searchParams = ref({
current: 1,
pageSize: 10,
sortField: "id",
sortOrder: "ascend",
sortOrder: "descend",
orderNumber: "",
orderStatus: ""
});
@ -252,7 +292,7 @@ const handleTableChange = (pag: any, _filters: any, sorter: any) => {
} else {
searchParams.value.sortField = "id";
searchParams.value.sortOrder = "ascend";
searchParams.value.sortOrder = "descend";
}
// 同步到分页组件
@ -306,7 +346,7 @@ const reset = () => {
current: 1,
pageSize: 10,
sortField: "id",
sortOrder: "ascend",
sortOrder: "descend",
orderNumber: "",
orderStatus: ""
};
@ -347,4 +387,11 @@ const reset = () => {
background-color: #ffa940;
border-color: #ffa940;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>

View File

@ -0,0 +1,307 @@
<template>
<form @submit.prevent="handleSubmit" class="modern-form">
<h2 class="form-title">员工账号申请须知</h2>
<!-- 富文本编辑器区域 - 修改为50%宽度 -->
<div class="rich-text-container">
<div class="rich-text-columns">
<div class="rich-text-group">
<span class="label-text">须知详情</span>
<RichTextEditor
v-model="formData.detail"
:disable="false"
@content-change="(html:any) => formData.detail = html"
/>
</div>
</div>
</div>
<button type="submit" class="submit-button">
<span>立即创建</span>
<div class="button-sparkles"></div>
</button>
</form>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import RichTextEditor from '../components/RichTextEditor.vue';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import myAxios from "../../api/myAxios.ts";
interface CourseForm {
name: string;
type: string;
image: string;
detail: string;
promoCodeDesc: string;
originPrice: number;
discountPrice: number;
firstLevelRate: number;
secondLevelRate: number;
}
const fileName = ref('');
// 新增价格错误状态
const priceError = ref('');
const formData = reactive<CourseForm>({
name: '',
type: '',
image: '',
detail: '',
promoCodeDesc: '',
originPrice: 0,
discountPrice: 0,
firstLevelRate: 0,
secondLevelRate: 0
});
const encode64 = (text: string): string => {
return btoa(
encodeURIComponent(text).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
))
};
const encryptValue = (value: any, key: string): any => {
// 数值型字段直接返回,不加密
if (key === 'originPrice' || key === 'discountPrice' ||
key === 'image' || key ==='name'||key === 'type') {
return value;
}
try {
const valueString = typeof value === 'object'
? JSON.stringify(value)
: String(value);
return encode64(valueString);
} catch (error) {
console.error('Base64编码失败:', error);
return value;
}
};
const handleSubmit = async () => {
// 重置错误状态
priceError.value = '';
try {
const storedToken = localStorage.getItem('token');
const encryptedFormData: Record<string, any> = {};
Object.entries(formData).forEach(([key, value]) => {
if (value === null || value === undefined || value === '') return;
encryptedFormData[key] = encryptValue(value, key);
});
const res: any = await myAxios.post(`/course/add`, encryptedFormData, {
headers: {
'Content-Type': 'application/json',
'Authorization': storedToken
}
});
if (res.code === 1) {
alert('须知创建成功!');
Object.assign(formData, {
name: '',
type: '',
image: '',
detail: '',
promoCodeDesc: '',
originPrice: 0,
discountPrice: 0,
firstLevelRate: 0,
secondLevelRate: 0
});
fileName.value = '';
} else {
alert(`创建失败:${res.message}`);
}
} catch (error) {
console.error('请求失败:', error);
alert('提交失败,请检查控制台获取详细信息');
}
};
</script>
<style scoped>
.modern-form {
max-width: 90%;
margin: 2rem auto;
padding: 2.5rem;
background: white;
border-radius: 1.5rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
font-family: 'Segoe UI', system-ui, sans-serif;
}
.form-title {
text-align: center;
font-size: 1.8rem;
color: #2c3e50;
margin-bottom: 2rem;
font-weight: 600;
letter-spacing: 0.5px;
}
.label-text {
display: block;
margin-bottom: 0.6rem;
color: #4a5568;
font-size: 0.9rem;
font-weight: 500;
}
.select-wrapper:focus-within .select-arrow {
transform: translateY(-50%) rotate(180deg);
}
/* 下拉选项样式 */
.select-field option {
padding: 8px 12px;
background: white;
color: #4a5568;
}
.select-field option:hover {
background: #f1f5f9;
}
.select-field option:checked {
background: #6366f1;
color: white;
}
.submit-button {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 1rem;
margin-top: 1.5rem;
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
color: white;
border: none;
border-radius: 0.75rem;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.submit-button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.3);
}
.button-sparkles {
position: absolute;
width: 20px;
height: 20px;
background: rgba(255,255,255,0.4);
border-radius: 50%;
animation: sparkle 1.5s infinite;
}
@keyframes sparkle {
0% { transform: scale(0) translate(0,0); }
50% { transform: scale(1) translate(100px, -50px); }
100% { transform: scale(0) translate(200px, -100px); }
}
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
}
.modern-form {
padding: 1.5rem;
margin: 1rem;
}
}
.rich-text-container {
margin-top: 1.5rem;
width: 100%;
}
.rich-text-group {
width: 100%;
height: 100%;
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
overflow: hidden;
transition: all 0.3s ease;
min-height: 320px;
flex-grow: 1;
}
@media (max-width: 768px) {
.rich-text-columns {
grid-template-columns: 1fr;
}
}
.rich-text-group:focus-within {
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
.rich-text-group .label-text {
font-size: 0.95rem;
font-weight: 600;
color: #3b4151;
padding: 12px 12px 0;
}
.phone-section-content * {
max-width: 100%;
}
.phone-section-content img {
max-width: 100%;
height: auto;
border-radius: 8px;
margin: 10px 0;
}
.phone-section-content h1,
.phone-section-content h2,
.phone-section-content h3 {
color: #2c3e50;
margin-top: 15px;
margin-bottom: 10px;
}
.phone-section-content p {
margin-bottom: 10px;
}
.phone-section-content ul,
.phone-section-content ol {
margin-left: 20px;
margin-bottom: 10px;
}
</style>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, reactive, onMounted, h } from "vue";
import { ref, reactive, onMounted, h ,nextTick} from "vue";
import { useRouter } from "vue-router";
import { message } from "ant-design-vue";
import type { TableProps } from 'ant-design-vue';
@ -21,8 +21,7 @@ const columns = [
key: 'name',
width: 120,
fixed: 'left',
align: 'center',
sorter: true
align: 'center'
},
{
title: '手机号',
@ -255,6 +254,50 @@ onMounted(() => {
fetchAdvancementData();
});
const handleNameInput = (event: Event) => {
const input = event.target as HTMLInputElement;
const originalValue = input.value;
// 过滤掉所有非中文字符(包括全角字符)
const filteredValue = originalValue.replace(/[^\u4e00-\u9fa5]/g, '');
// 更新输入框的值
if (originalValue !== filteredValue) {
searchName.value = filteredValue;
// 强制更新输入框值(解决某些情况下显示残留问题)
nextTick(() => {
input.value = filteredValue;
});
}
};
const handlePaste = (event: ClipboardEvent) => {
const clipboardData = event.clipboardData || (window as any).clipboardData;
const pastedText = clipboardData.getData('text');
// 检查粘贴内容是否包含非中文字符
if (/[^\u4e00-\u9fa5]/.test(pastedText)) {
event.preventDefault();
message.warning('只能粘贴中文字符');
}
};
const filterPhoneInput = (e: Event) => {
const input = e.target as HTMLInputElement;
let value = input.value;
// 1. 移除非数字字符
value = value.replace(/\D/g, '');
// 2. 限制最多11位数字
if (value.length > 11) {
value = value.slice(0, 11);
}
// 更新输入框值
input.value = value;
searchPhone.value = value;
};
</script>
<template>
@ -265,12 +308,14 @@ onMounted(() => {
<a-form-item label="申请人姓名">
<a-input-search
style="width: 300px"
placeholder="请输入姓名"
placeholder="请输入姓名(仅中文)"
class="custom-search"
enter-button
v-model:value="searchName"
@pressEnter="handleSearch"
@search="handleSearch"
@input="handleNameInput"
@paste="handlePaste"
/>
</a-form-item>
<a-form-item label="手机号">
@ -282,6 +327,7 @@ onMounted(() => {
@search="handleSearch"
enter-button
class="custom-search"
@input="filterPhoneInput"
/>
</a-form-item>
<a-button @click="reset">重置</a-button>
@ -379,38 +425,11 @@ onMounted(() => {
border-right-color: #ffa940;
}
/* 审核人选择弹窗样式 */
.supervisor-list {
max-height: 400px;
overflow-y: auto;
padding: 10px;
}
.radio-group {
width: 100%;
}
.supervisor-item {
display: flex;
align-items: center;
padding: 8px 0;
width: 100%;
}
.supervisor-info {
display: flex;
flex-direction: column;
margin-left: 12px;
}
.supervisor-id {
font-size: 12px;
color: #666;
}
.supervisor-name {
font-size: 14px;
font-weight: 500;
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
:deep(.ant-list-item) {
@ -427,17 +446,4 @@ onMounted(() => {
align-items: flex-start;
}
/* 操作按钮样式 */
.action-btn {
margin: 0 4px;
font-size: 14px;
}
.action-btn.primary {
color: #1890ff;
}
.action-btn.danger {
color: #ff4d4f;
}
</style>

View File

@ -124,6 +124,7 @@
:ok-text="'确认驳回'"
:cancel-text="'取消'"
okType="danger"
class="reject-modal"
>
<a-alert type="warning" show-icon class="reject-alert">
<template #message>
@ -135,18 +136,19 @@
</a-alert>
<div class="reject-form">
<a-form layout="vertical">
<a-form-item label="驳回原因" required>
<a-textarea
v-model:value="rejectReason"
placeholder="请输入详细的驳回原因..."
:rows="4"
:maxlength="200"
show-count
class="reject-reason"
/>
</a-form-item>
</a-form>
<div class="reject-header">
<h4 class="reject-title">* 驳回原因</h4>
<div class="char-counter">
{{ rejectReason.length }} / 200
</div>
</div>
<a-textarea
v-model:value="rejectReason"
placeholder="请输入详细的驳回原因..."
:rows="4"
:maxlength="200"
class="reject-reason"
/>
</div>
</a-modal>
</div>
@ -632,7 +634,11 @@ const submitReject = async () => {
padding: 24px;
}
/* 驳回弹窗样式 */
/* 驳回弹窗样式优化 */
.reject-modal :deep(.ant-modal-body) {
padding: 24px;
}
.reject-alert {
margin-bottom: 20px;
border-radius: 8px;
@ -645,8 +651,37 @@ const submitReject = async () => {
font-weight: 500;
}
.divider {
height: 1px;
background: #f0f0f0;
margin: 20px 0;
}
.reject-form {
padding: 10px;
padding: 0 10px;
margin-bottom: 24px;
}
.reject-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.reject-title {
margin: 0;
font-size: 14px;
font-weight: 500;
color: #333;
}
.char-counter {
font-size: 12px;
color: #999;
background: #f5f5f5;
padding: 2px 8px;
border-radius: 10px;
}
.reject-reason {
@ -655,6 +690,8 @@ const submitReject = async () => {
padding: 12px;
border: 1px solid #d9d9d9;
transition: all 0.3s;
width: 100%;
font-size: 14px;
}
.reject-reason:focus {
@ -662,6 +699,13 @@ const submitReject = async () => {
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.action-buttons {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 16px;
}
/* 空状态样式 */
:deep(.ant-empty) {
margin: 40px 0;

View File

@ -294,6 +294,7 @@ const updateProportionRate = async () => {
// 修复语法错误:移除命名参数
proportionRate.value = parseFloat(rateValue.toFixed(2)).toString();
visible.value = false;
fetchEmployeePerformance();
} else {
message.error(response.message || "更新抽成比例失败");
}
@ -525,4 +526,5 @@ const filterRateInput = (e: Event) => {
background-color: #ffa940;
border-color: #ffa940;
}
</style>

View File

@ -167,6 +167,33 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
queryParams.startDate = dateStrings[0] || '';
queryParams.endDate = dateStrings[1] || '';
};
const handleSearchPhoneInput = (e: any) => {
let value = e.target.value;
// 只允许输入数字并截取前11位
const newValue = value.replace(/[^0-9]/g, '').slice(0, 11);
// 直接更新 queryParams.phoneNumber
queryParams.phoneNumber = newValue;
};
// 新增 onKeyDown 事件处理函数
const handleKeyDown = (e: KeyboardEvent) => {
const allowedKeys = [
'Backspace',
'Delete',
'ArrowLeft',
'ArrowRight',
'Tab',
];
// 只允许输入数字和控制键
if (!/[0-9]/.test(e.key) && !allowedKeys.includes(e.key)) {
e.preventDefault();
}
};
</script>
<template>
@ -212,6 +239,9 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
placeholder="手机号"
style="width: 180px; margin-right: 10px;"
allow-clear
:maxlength="11"
@input="handleSearchPhoneInput"
@keydown="handleKeyDown"
/>
<Input

View File

@ -25,7 +25,7 @@ const columns = [
align: 'center'
},
{
title: '主管姓名',
title: '学校名称',
dataIndex: 'nickName',
key: 'nickName',
width: 100,
@ -290,6 +290,7 @@ const updateProportionRate = async () => {
message.success("抽成比例更新成功");
proportionRate.value = rateValue.toFixed(2);
visible.value = false;
fetchManagerPerformance()
} else {
message.error(response.message || "更新抽成比例失败");
}
@ -414,11 +415,11 @@ const settlement = async () => {
<!-- 搜索框 -->
<div class="search-box">
<a-form layout="inline">
<a-space>
<a-form-item label="主管姓名">
<div class="flex-container">
<a-form-item label="学校名称">
<a-input
style="width: 300px;border: 1px solid #ffa940;"
placeholder="请输入主管姓名"
placeholder="请输入学校名称"
v-model:value="searchName"
@click="handleSearch"
@input="filterNameInput"
@ -434,12 +435,18 @@ const settlement = async () => {
@input="filterPhoneInput"
/>
</a-form-item>
<a-button @click="handleSearch" style="margin-right: 10px" class="custom-button">搜索</a-button>
<a-button @click="reset">重置</a-button>
抽成占比<a-tag color="orange">{{ proportionRate }}</a-tag>
<a-button @click="openRateModal" style="margin-left: 10px" class="custom-button">修改比例</a-button>
<a-button @click="settlement" style="margin-left: 10px" class="custom-button">一键结算</a-button>
</a-space>
<!-- 将按钮和标签包裹在button-group中 -->
<div class="button-group">
<a-button @click="handleSearch" class="custom-button">搜索</a-button>
<a-button @click="reset" class="custom-button">重置</a-button>
<div class="proportion-tag">
抽成占比<a-tag color="orange">{{ proportionRate }}</a-tag>
</div>
<a-button @click="openRateModal" class="custom-button">修改比例</a-button>
<a-button @click="settlement" class="custom-button">一键结算</a-button>
</div>
</div>
</a-form>
</div>
<!-- 修改比例弹窗 -->
@ -505,6 +512,45 @@ const settlement = async () => {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* 使用弹性盒子布局并允许换行 */
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
width: 100%;
}
/* 表单行样式 */
.search-box .ant-form-item {
margin-bottom: 0;
display: flex;
align-items: center;
flex: 1 1 auto;
}
/* 按钮组容器 */
.button-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
flex: 1 1 100%; /* 默认占据整行 */
}
/* 抽成比例标签容器 */
.proportion-tag {
display: flex;
align-items: center;
gap: 8px;
}
/* 在中等屏幕以上时调整按钮组布局 */
@media (min-width: 992px) {
.button-group {
flex: 0 1 auto; /* 根据内容自适应宽度 */
}
}
/* 搜索框输入框聚焦和悬浮状态边框为橙色 */
.search-box .custom-search :deep(.ant-input:hover),
.search-box .custom-search :deep(.ant-input:focus) {
@ -517,6 +563,7 @@ const settlement = async () => {
background-color: #ffa940;
color: #fff;
border: 1px solid #ffa940;
white-space: nowrap; /* 防止按钮文字换行 */
}
.custom-button:hover,
@ -542,4 +589,21 @@ const settlement = async () => {
.custom-search :deep(.ant-input) {
border-right-color: #ffa940;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.search-box .ant-form-item {
min-width: 200px;
}
}
@media (max-width: 768px) {
.search-box .ant-form-item {
width: 100%;
}
.search-box .ant-input {
width: 100% !important;
}
}
</style>

View File

@ -67,7 +67,7 @@ const total = ref(0);
// 表格列定义
const columns = [
{ title: '用户昵称', dataIndex: 'nickName', key: 'nickName' },
{ title: '学校名称', dataIndex: 'nickName', key: 'nickName' },
{ title: '手机号', dataIndex: 'phoneNumber', key: 'phoneNumber' },
{ title: '员工数量', dataIndex: 'empCount', key: 'empCount' },
{ title: '推广人数', dataIndex: 'promoCount', key: 'promoCount' },
@ -154,6 +154,10 @@ const resetSearch = () => {
queryParams.endDate = '';
queryParams.sortField = '';
queryParams.sortOrder = '';
// 重置当前页码为1
queryParams.current = 1;
fetchPerformanceRank();
};
@ -162,6 +166,40 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
queryParams.startDate = dateStrings[0] || '';
queryParams.endDate = dateStrings[1] || '';
};
// 处理搜索操作(新增方法)
const handleSearch = () => {
// 重置当前页码为1
queryParams.current = 1;
fetchPerformanceRank();
};
const handleSearchPhoneInput = (e: any) => {
let value = e.target.value;
// 只允许输入数字并截取前11位
const newValue = value.replace(/[^0-9]/g, '').slice(0, 11);
// 直接更新 queryParams.phoneNumber
queryParams.phoneNumber = newValue;
};
// 新增 onKeyDown 事件处理函数
const handleKeyDown = (e: KeyboardEvent) => {
const allowedKeys = [
'Backspace',
'Delete',
'ArrowLeft',
'ArrowRight',
'Tab',
];
// 只允许输入数字和控制键
if (!/[0-9]/.test(e.key) && !allowedKeys.includes(e.key)) {
e.preventDefault();
}
};
</script>
<template>
@ -204,6 +242,9 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
v-model:value="queryParams.phoneNumber"
placeholder="手机号"
style="width: 150px; margin-right: 10px;"
:maxlength="11"
@input="handleSearchPhoneInput"
@keydown="handleKeyDown"
/>
<Input
@ -219,7 +260,8 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
style="margin-right: 10px; width: 350px;"
/>
<Button type="primary" @click="fetchPerformanceRank" style="margin-right: 10px;">
<!-- 修改这里使用新的handleSearch方法 -->
<Button type="primary" @click="handleSearch" style="margin-right: 10px;">
搜索
</Button>
@ -265,12 +307,11 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
</template>
<style scoped>
/* 原有样式保持不变 */
.performance-container {
padding: 20px;
/* 温馨的乳白色背景,带一点暖色调 */
background: #fffaf0;
border-radius: 12px;
/* 轻柔的暖色阴影 */
box-shadow: 0 4px 12px rgba(255, 164, 64, 0.2);
transition: transform 0.3s;
}
@ -288,7 +329,6 @@ const handleDateChange = (_: any, dateStrings: [string, string]) => {
h2 {
margin: 0;
/* 使用主题色 */
color: #ffa940;
font-size: 20px;
font-weight: 600;
@ -297,7 +337,6 @@ h2 {
.filter-container {
width: 100%;
margin-top: 15px;
/* 柔和的卡片背景 */
background: #fff5e6;
border: 1px solid #ffd591;
border-radius: 8px;
@ -326,8 +365,6 @@ h2 {
text-align: right;
}
/* 单元格边框去掉横线,更显高级 */
:deep(.ant-table-cell) {
border-bottom: none;
@ -372,4 +409,4 @@ h2 {
:deep(.ant-picker-focused) {
box-shadow: 0 0 0 2px rgba(255, 164, 64, 0.2) !important;
}
</style>
</style>

View File

@ -49,7 +49,7 @@
</template>
</a-form-item>
<a-form-item label="头像" name="userAvatar" required>
<a-form-item label="头像" name="userAvatar">
<a-upload
name="file"
list-type="picture-card"
@ -216,7 +216,7 @@
</a-input>
</a-form-item>
<a-form-item label="头像" name="userAvatar" required>
<a-form-item label="头像" name="userAvatar">
<a-upload
name="file"
list-type="picture-card"
@ -339,7 +339,7 @@
</template>
<script lang="ts" setup>
import { onMounted, ref,computed } from "vue";
import { onMounted, ref,computed,nextTick } from "vue";
import myAxios from "../../api/myAxios.ts";
import { message, Modal } from "ant-design-vue";
import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
@ -381,19 +381,19 @@ const handleUpload = async ({ file }: { file: File }) => {
uploadLoading.value = true;
const storedToken = localStorage.getItem('token');
const res:any = await myAxios.post('/file/upload?biz=avatar', form, {
headers: {
Authorization: storedToken,
}
});
console.log(res)
if (res.code === 1) {
formData.value.userAvatar = res.data;
previewImage.value = URL.createObjectURL(file);
message.success('上传成功');
// 关键:清除整个表单的校验状态
formRef.value?.clearValidate();
} else {
message.error(res.message || '上传失败');
}
@ -500,6 +500,13 @@ const formRules = {
},
trigger: ['input', 'blur']
}
],
userAvatar: [
{
required: true,
message: '请上传头像',
trigger: 'change'
}
]
}
@ -695,6 +702,13 @@ const editFormRules = {
},
trigger: ['input', 'blur']
}
],
userAvatar: [
{
required: true,
message: '请上传头像',
trigger: 'change'
}
]
};
@ -844,7 +858,8 @@ const handlePhoneSearch = async () => {
{
current: 1,
pageSize: 10,
phoneNumber: searchPhone.value
phoneNumber: searchPhone.value,
userRole: "admin"
},
{ headers: { Authorization: storedToken } }
);
@ -1012,7 +1027,7 @@ const editForm = ref({
userAccount: '',
userPassword: '',
invitationCode: '',
userRole: '',
userRole: 'admin',
parentUserId: 0,
SuperUserList: ''
});
@ -1040,6 +1055,9 @@ const handleEditUpload = async ({ file }: { file: File }) => {
editForm.value.userAvatar = res.data;
editPreviewImage.value = URL.createObjectURL(file);
message.success('头像更新成功');
// 关键:清除整个编辑表单的校验状态
editFormRef.value?.clearValidate();
} else {
message.error(res.message || '头像上传失败');
}
@ -1050,6 +1068,9 @@ const handleEditUpload = async ({ file }: { file: File }) => {
editUploadLoading.value = false;
}
};
const showDrawer = (record: any) => {
selectedUser.value = record;
editForm.value = {
@ -1162,6 +1183,7 @@ const formRef = ref();
const showModal = () => {
openUser.value = true;
formData.value = {
@ -1173,6 +1195,9 @@ const showModal = () => {
};
previewImage.value = '';
nextTick(() => {
formRef.value?.clearValidate();
});
};
const handleOk = (e: MouseEvent) => {
@ -1497,4 +1522,11 @@ const handleSubmit = async () => {
:deep(.ant-checkbox-wrapper-disabled) {
display: none;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>

View File

@ -743,4 +743,10 @@ const showDrawer = (record: any) => {
:deep(.ant-checkbox-wrapper-disabled) {
display: none;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>

View File

@ -804,4 +804,11 @@ const showDrawer = (record: any) => {
:deep(.ant-checkbox-wrapper-disabled) {
display: none;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>

View File

@ -695,4 +695,11 @@ const handleTableChange = (pag: any, _: any, sorter: any) => {
:deep(.ant-checkbox-wrapper-disabled) {
display: none;
}
:deep(.custom-search .ant-input:focus),
:deep(.custom-search .ant-input:hover),
:deep(.custom-search .ant-input-focused) {
border-color: #ffa940 !important;
box-shadow: 0 0 0 2px rgba(255, 169, 64, 0.2) !important;
}
</style>