[dev]update profile

This commit is contained in:
susie-laptop 2025-05-09 15:02:51 -04:00
parent 5502bd579c
commit b4d708d994
3 changed files with 314 additions and 273 deletions

View File

@ -1,22 +1,22 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from "react-redux";
import { updateProfileThunk } from '../store/auth/auth.thunk'; import { updateProfileThunk } from "../store/auth/auth.thunk";
import ChangePasswordModal from './ChangePasswordModal'; import ChangePasswordModal from "./ChangePasswordModal";
// //
const departmentGroups = { const departmentGroups = {
达人部门: ['达人'], 达人部门: ["达人"],
商务部门: ['商务'], 商务部门: ["商务"],
样本中心: ['样本'], 样本中心: ["样本"],
产品部门: ['产品'], 产品部门: ["产品"],
AI自媒体: ['AI自媒体'], AI自媒体: ["AI自媒体"],
HR: ['HR'], HR: ["HR"],
技术部门: ['技术'], 技术部门: ["技术"],
}; };
function UserSettingsModal({ show, onClose }) { function UserSettingsModal({ show, onClose }) {
const { user, loading } = useSelector((state) => state.auth); const { user, loading } = useSelector((state) => state.auth);
const [lastPasswordChange] = useState('30天前'); // This would come from backend in real app const [lastPasswordChange] = useState("30天前"); // This would come from backend in real app
const [formData, setFormData] = useState({}); const [formData, setFormData] = useState({});
const [showChangePassword, setShowChangePassword] = useState(false); const [showChangePassword, setShowChangePassword] = useState(false);
// //
@ -52,11 +52,11 @@ function UserSettingsModal({ show, onClose }) {
const handleInputChange = (e) => { const handleInputChange = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
if (name === 'department') { if (name === "department") {
setFormData({ setFormData({
...formData, ...formData,
[name]: value, [name]: value,
['group']: '', ["group"]: "",
}); });
} else { } else {
setFormData({ setFormData({
@ -69,7 +69,7 @@ function UserSettingsModal({ show, onClose }) {
if (errors[name]) { if (errors[name]) {
setErrors({ setErrors({
...errors, ...errors,
[name]: '', [name]: "",
}); });
} }
}; };
@ -79,12 +79,12 @@ function UserSettingsModal({ show, onClose }) {
setSubmitted(true); setSubmitted(true);
if (validateForm()) { if (validateForm()) {
console.log('Form submitted successfully!'); console.log("Form submitted successfully!");
console.log('Update data:', formData); console.log("Update data:", formData);
try { try {
await dispatch(updateProfileThunk(formData)).unwrap(); await dispatch(updateProfileThunk(formData)).unwrap();
} catch (error) { } catch (error) {
console.error('Signup failed:', error); console.error("Signup failed:", error);
} }
} }
}; };
@ -92,21 +92,23 @@ function UserSettingsModal({ show, onClose }) {
const validateForm = () => { const validateForm = () => {
const newErrors = {}; const newErrors = {};
if (!formData.email) { if (!formData.email) {
newErrors.email = 'Email is required'; newErrors.email = "Email is required";
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(formData.email)) { } else if (
newErrors.email = 'Invalid email address'; !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(formData.email)
) {
newErrors.email = "Invalid email address";
} }
if (!formData.name) { if (!formData.name) {
newErrors.name = 'Name is required'; newErrors.name = "Name is required";
} }
if (!formData.department) { if (!formData.department) {
newErrors.department = '请选择部门'; newErrors.department = "请选择部门";
} }
if (!formData.group) { if (!formData.group) {
newErrors.group = '请选择组别'; newErrors.group = "请选择组别";
} }
setErrors(newErrors); setErrors(newErrors);
@ -114,55 +116,73 @@ function UserSettingsModal({ show, onClose }) {
}; };
return ( return (
<div className='modal show d-block' style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}> <div
<div className='modal-dialog modal-dialog-centered'> className="modal show d-block"
<form className='modal-content' onSubmit={handleSubmit}> style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
<div className='modal-header border-0'> >
<h5 className='modal-title'>个人设置</h5> <div className="modal-dialog modal-dialog-centered">
<button type='button' className='btn-close' onClick={onClose}></button> <form className="modal-content" onSubmit={handleSubmit}>
<div className="modal-header border-0">
<h5 className="modal-title">个人设置</h5>
<button
type="button"
className="btn-close"
onClick={onClose}
></button>
</div> </div>
<div className='modal-body'> <div className="modal-body">
<div className='mb-4'> <div className="mb-4">
<h6 className='text-secondary mb-3'>个人信息</h6> <h6 className="text-secondary mb-3">个人信息</h6>
<div className='mb-3'> <div className="mb-3">
<label className='form-label text-secondary'>用户名</label> <label className="form-label text-secondary">用户名</label>
<input type='text' className='form-control' value={user?.username || ''} readOnly />
</div>
<div className='mb-3'>
<label className='form-label text-secondary'>姓名</label>
<input <input
type='text' type="text"
className='form-control' className="form-control"
value={formData?.name || ''} value={user?.username || ""}
readOnly
/>
</div>
<div className="mb-3">
<label className="form-label text-secondary">姓名</label>
<input
type="text"
className="form-control"
value={formData?.name || ""}
name="name"
onChange={handleInputChange} onChange={handleInputChange}
disabled={loading} disabled={loading}
/> />
{submitted && errors.name && <div className='invalid-feedback'>{errors.name}</div>} {submitted && errors.name && (
<div className="invalid-feedback">{errors.name}</div>
)}
</div> </div>
<div className='mb-3'> <div className="mb-3">
<label className='form-label text-secondary'>邮箱</label> <label className="form-label text-secondary">邮箱</label>
<input <input
type='email' type="email"
className='form-control' name="email"
value={formData?.email || 'admin@ooin.com'} className="form-control"
value={formData?.email || "admin@ooin.com"}
onChange={handleInputChange} onChange={handleInputChange}
disabled={loading} disabled={loading}
/> />
{submitted && errors.email && <div className='invalid-feedback'>{errors.email}</div>} {submitted && errors.email && (
<div className="invalid-feedback">{errors.email}</div>
)}
</div> </div>
<div className='mb-3'> <div className="mb-3">
<select <select
className={`form-select form-select-lg${ className={`form-select form-select-lg${
submitted && errors.department ? ' is-invalid' : '' submitted && errors.department ? " is-invalid" : ""
}`} }`}
id='department' id="department"
name='department' name="department"
value={formData.department} value={formData.department}
onChange={handleInputChange} onChange={handleInputChange}
disabled={loading} disabled={loading}
required required
> >
<option value='' disabled> <option value="" disabled>
选择部门 选择部门
</option> </option>
{Object.keys(departmentGroups).map((dept, index) => ( {Object.keys(departmentGroups).map((dept, index) => (
@ -172,23 +192,23 @@ function UserSettingsModal({ show, onClose }) {
))} ))}
</select> </select>
{submitted && errors.department && ( {submitted && errors.department && (
<div className='invalid-feedback'>{errors.department}</div> <div className="invalid-feedback">{errors.department}</div>
)} )}
</div> </div>
<div className='mb-3'> <div className="mb-3">
<select <select
className={`form-select form-select-lg${ className={`form-select form-select-lg${
submitted && errors.group ? ' is-invalid' : '' submitted && errors.group ? " is-invalid" : ""
}`} }`}
id='group' id="group"
name='group' name="group"
value={formData.group} value={formData.group}
onChange={handleInputChange} onChange={handleInputChange}
disabled={loading || !formData.department} disabled={loading || !formData.department}
required required
> >
<option value='' disabled> <option value="" disabled>
{formData.department ? '选择组别' : '请先选择部门'} {formData.department ? "选择组别" : "请先选择部门"}
</option> </option>
{availableGroups.map((group, index) => ( {availableGroups.map((group, index) => (
<option key={index} value={group}> <option key={index} value={group}>
@ -196,22 +216,26 @@ function UserSettingsModal({ show, onClose }) {
</option> </option>
))} ))}
</select> </select>
{submitted && errors.group && <div className='invalid-feedback'>{errors.group}</div>} {submitted && errors.group && (
<div className="invalid-feedback">{errors.group}</div>
)}
</div> </div>
</div> </div>
<div className='mb-4'> <div className="mb-4">
<h6 className='text-secondary mb-3'>安全设置</h6> <h6 className="text-secondary mb-3">安全设置</h6>
<div className='d-flex justify-content-between align-items-center p-3 bg-light rounded'> <div className="d-flex justify-content-between align-items-center p-3 bg-light rounded">
<div> <div>
<div className='d-flex align-items-center gap-2'> <div className="d-flex align-items-center gap-2">
<i className='bi bi-key'></i> <i className="bi bi-key"></i>
<span>修改密码</span> <span>修改密码</span>
</div> </div>
<small className='text-secondary'>上次修改{lastPasswordChange}</small> <small className="text-secondary">
上次修改{lastPasswordChange}
</small>
</div> </div>
<button <button
className='btn btn-outline-dark btn-sm' className="btn btn-outline-dark btn-sm"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
setShowChangePassword(true); setShowChangePassword(true);
@ -222,70 +246,90 @@ function UserSettingsModal({ show, onClose }) {
</div> </div>
</div> </div>
<div className='d-none mb-4'> <div className="d-none mb-4">
<h6 className='text-secondary mb-3'>安全设置</h6> <h6 className="text-secondary mb-3">安全设置</h6>
<div className='d-flex justify-content-between align-items-center p-3 bg-light rounded'> <div className="d-flex justify-content-between align-items-center p-3 bg-light rounded">
<div> <div>
<div className='d-flex align-items-center gap-2'> <div className="d-flex align-items-center gap-2">
<i className='bi bi-key'></i> <i className="bi bi-key"></i>
<span>修改密码</span> <span>修改密码</span>
</div> </div>
<small className='text-secondary'>上次修改{lastPasswordChange}</small> <small className="text-secondary">
上次修改{lastPasswordChange}
</small>
</div> </div>
<button className='btn btn-outline-dark btn-sm'>修改</button> <button className="btn btn-outline-dark btn-sm">修改</button>
</div> </div>
<div className='d-flex justify-content-between align-items-center p-3 bg-light rounded mt-3'> <div className="d-flex justify-content-between align-items-center p-3 bg-light rounded mt-3">
<div> <div>
<div className='d-flex align-items-center gap-2'> <div className="d-flex align-items-center gap-2">
<i className='bi bi-shield-check'></i> <i className="bi bi-shield-check"></i>
<span>双重认证</span> <span>双重认证</span>
</div> </div>
<small className='text-secondary'>增强账户安全性</small> <small className="text-secondary">增强账户安全性</small>
</div> </div>
<button className='btn btn-outline-dark btn-sm'>设置</button> <button className="btn btn-outline-dark btn-sm">设置</button>
</div> </div>
</div> </div>
<div className='d-none'> <div className="d-none">
<h6 className='text-secondary mb-3'>通知设置</h6> <h6 className="text-secondary mb-3">通知设置</h6>
<div className='form-check form-switch mb-3 dark-switch'> <div className="form-check form-switch mb-3 dark-switch">
<input <input
className='form-check-input' className="form-check-input"
type='checkbox' type="checkbox"
id='notificationSwitch1' id="notificationSwitch1"
defaultChecked defaultChecked
/> />
<label className='form-check-label' htmlFor='notificationSwitch1'> <label
className="form-check-label"
htmlFor="notificationSwitch1"
>
访问请求通知 访问请求通知
</label> </label>
<div className='text-secondary small'>新的数据集访问申请通知</div> <div className="text-secondary small">
新的数据集访问申请通知
</div> </div>
<div className='form-check form-switch dark-switch'> </div>
<div className="form-check form-switch dark-switch">
<input <input
className='form-check-input' className="form-check-input"
type='checkbox' type="checkbox"
id='notificationSwitch2' id="notificationSwitch2"
defaultChecked defaultChecked
/> />
<label className='form-check-label' htmlFor='notificationSwitch2'> <label
className="form-check-label"
htmlFor="notificationSwitch2"
>
安全提醒 安全提醒
</label> </label>
<div className='text-secondary small'>异常登录和权限变更提醒</div> <div className="text-secondary small">
异常登录和权限变更提醒
</div> </div>
</div> </div>
</div> </div>
<div className='modal-footer border-0'> </div>
<button type='button' disabled={loading} className='btn btn-outline-dark' onClick={onClose}> <div className="modal-footer border-0">
<button
type="button"
disabled={loading}
className="btn btn-outline-dark"
onClick={onClose}
>
取消 取消
</button> </button>
<button type='submit' className='btn btn-dark' disabled={loading}> <button type="submit" className="btn btn-dark" disabled={loading}>
保存更改 保存更改
</button> </button>
</div> </div>
</form> </form>
</div> </div>
{showChangePassword && ( {showChangePassword && (
<ChangePasswordModal show={showChangePassword} onClose={() => setShowChangePassword(false)} /> <ChangePasswordModal
show={showChangePassword}
onClose={() => setShowChangePassword(false)}
/>
)} )}
</div> </div>
); );

View File

@ -47,15 +47,12 @@ export default function Chat() {
// If we have a knowledgeBaseId but no chatId, check if we have an existing chat or create a new one // If we have a knowledgeBaseId but no chatId, check if we have an existing chat or create a new one
useEffect(() => { useEffect(() => {
console.log('Chat.jsx: chatHistory', chatHistory);
// knowledgeBaseId chatId // knowledgeBaseId chatId
if (knowledgeBaseId && !chatId && status === 'succeeded' && !status.includes('loading')) { if (knowledgeBaseId && !chatId && status === 'succeeded' && !status.includes('loading')) {
console.log('Chat.jsx: 创建新聊天...'); console.log('Chat.jsx: 创建新聊天...');
// ID () // ID ()
const knowledgeBaseIds = knowledgeBaseId.split(',').map((id) => id.trim()); const knowledgeBaseIds = knowledgeBaseId.split(',').map((id) => id.trim());
console.log('Chat.jsx: 处理知识库ID列表:', knowledgeBaseIds);
// - 使API // - 使API
dispatch( dispatch(

View File

@ -6,8 +6,8 @@ import KnowledgeBaseDetail from '../pages/KnowledgeBase/Detail/KnowledgeBaseDeta
import Chat from '../pages/Chat/Chat'; import Chat from '../pages/Chat/Chat';
import PermissionsPage from '../pages/Permissions/PermissionsPage'; import PermissionsPage from '../pages/Permissions/PermissionsPage';
import Loading from '../components/Loading'; import Loading from '../components/Loading';
import Login from '../pages/Auth/Login'; import Login from '../pages/auth/Login';
import Signup from '../pages/Auth/Signup'; import Signup from '../pages/auth/Signup';
import ProtectedRoute from './protectedRoute'; import ProtectedRoute from './protectedRoute';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import NotificationSnackbar from '../components/NotificationSnackbar'; import NotificationSnackbar from '../components/NotificationSnackbar';