Browse Source

部门管理-用户管理

master
談蓝色 10 months ago
parent
commit
8142c9c264
  1. 1
      frontend/.env.example
  2. 16
      frontend/src/models/admin.js
  3. 114
      frontend/src/pages/Admin/Section/index.jsx
  4. 85
      frontend/src/pages/Admin/Users/NewUserModal/index.jsx
  5. 12
      frontend/src/pages/Admin/Users/index.jsx
  6. 6
      frontend/src/pages/DataAnalysis/DataAnalysis.css
  7. 7
      frontend/src/pages/DataAnalysis/index.jsx
  8. 10
      frontend/src/pages/Home/home.css
  9. 40
      frontend/src/pages/Home/index.jsx
  10. 30
      frontend/src/pages/ReportGeneration/ReportGeneration.css
  11. 29
      frontend/src/pages/Tendency/Tendency.css
  12. 3
      frontend/src/utils/constants.js

1
frontend/.env.example

@ -1,3 +1,4 @@
VITE_API_BASE='http://localhost:3001/api' # Use this URL when developing locally VITE_API_BASE='http://localhost:3001/api' # Use this URL when developing locally
# VITE_API_BASE='http://172.16.2.31:3001/api'
# VITE_API_BASE="https://$CODESPACE_NAME-3001.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/api" # for GitHub Codespaces # VITE_API_BASE="https://$CODESPACE_NAME-3001.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/api" # for GitHub Codespaces
# VITE_API_BASE='/api' # Use this URL deploying on non-localhost address OR in docker. # VITE_API_BASE='/api' # Use this URL deploying on non-localhost address OR in docker.

16
frontend/src/models/admin.js

@ -15,6 +15,7 @@ const Admin = {
return []; return [];
}); });
}, },
// 旧用户
newUser: async (data) => { newUser: async (data) => {
return await fetch(`${API_BASE}/admin/users/new`, { return await fetch(`${API_BASE}/admin/users/new`, {
method: "POST", method: "POST",
@ -27,6 +28,21 @@ const Admin = {
return { user: null, error: e.message }; return { user: null, error: e.message };
}); });
}, },
// 用户
newUserTo: async (data,depId) => {
return await fetch(`${API_BASE}/admin/users/add/${depId}`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify(data),
})
.then((res) => res.json())
.catch((e) => {
console.error(e);
return { user: null, error: e.message };
});
},
updateUser: async (userId, data) => { updateUser: async (userId, data) => {
return await fetch(`${API_BASE}/admin/user/${userId}`, { return await fetch(`${API_BASE}/admin/user/${userId}`, {
method: "POST", method: "POST",

114
frontend/src/pages/Admin/Section/index.jsx

@ -160,8 +160,7 @@ function DepartmentRow({ dept }) {
<td className="px-6 py-4 text-theme-text-secondary">{dept.orderNum}</td> <td className="px-6 py-4 text-theme-text-secondary">{dept.orderNum}</td>
<td className="px-6 py-4"> <td className="px-6 py-4">
<span <span
className={`px-2 py-1 rounded-full text-xs font-medium ${
dept.status === 0
className={`px-2 py-1 rounded-full text-xs font-medium ${dept.status === 0
? "bg-green-100 text-green-800" ? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800" : "bg-red-100 text-red-800"
}`} }`}
@ -239,71 +238,122 @@ function NewDepartmentModal({ closeModal }) {
// //
const handleSubmit = async () => { const handleSubmit = async () => {
await Admin.addDepts(formData); await Admin.addDepts(formData);
closeModal()
window.location.reload();
};
//
const handleCancel = () => {
closeModal(); closeModal();
}; };
return ( return (
<div className="p-6">
<h2 className="text-lg font-bold text-theme-text-primary mb-4">
<div className="p-6 bg-white w-[20%] rounded-lg shadow-sm border border-gray-100">
<h2 className="text-xl font-semibold text-gray-800 mb-6">
添加组织机构 添加组织机构
</h2> </h2>
<div className="flex flex-col gap-y-4">
<div className="flex flex-col gap-y-5">
{/* 上级组织机构选择器 */} {/* 上级组织机构选择器 */}
<div>
<label className="text-sm font-medium text-theme-text-secondary block mb-2">
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1">
上级组织机构 上级组织机构
</label> </label>
<TreeSelect <TreeSelect
treeData={treeData} //
value={formData.parentId} // ID
onChange={(value) =>
setFormData({ ...formData, parentId: value })
}
treeData={treeData}
value={formData.parentId}
onChange={(value) => setFormData({ ...formData, parentId: value })}
placeholder="请选择上级组织机构" placeholder="请选择上级组织机构"
className="w-full"
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
className="w-full rounded-md border-gray-300 hover:border-blue-400 focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
dropdownStyle={{
maxHeight: 400,
overflow: "auto",
borderRadius: "6px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
}}
dropdownClassName="bg-white border border-gray-200"
/> />
</div> </div>
{/* 组织机构名称输入框 */}
{/* 输入框组 */}
<div className="space-y-5">
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1 font-bold">
组织机构名称
</label>
<input <input
type="text" type="text"
placeholder="组织机构名称"
placeholder="请输入名称"
value={formData.deptName} value={formData.deptName}
onChange={(e) =>
setFormData({ ...formData, deptName: e.target.value })
}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
onChange={(e) => setFormData({ ...formData, deptName: e.target.value })}
className="w-[100%] border border-[#D9D9D9] rounded-md hover:border-blue-400 focus:border-blue-500 pt-[5px] pb-[5px] pl-[10px] text-[14px]"
/> />
</div>
{/* 排序输入框 */}
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1">
排序
</label>
<input <input
type="number" type="number"
placeholder="排序"
placeholder="请输入排序"
value={formData.orderNum} value={formData.orderNum}
onChange={(e) =>
setFormData({ ...formData, orderNum: Number(e.target.value) })
}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
onChange={(e) => setFormData({ ...formData, orderNum: Number(e.target.value) })}
className="w-[100%] border border-[#D9D9D9] rounded-md hover:border-blue-400 focus:border-blue-500 pt-[5px] pb-[5px] pl-[10px] text-[14px]"
/> />
</div>
{/* 状态选择器 */}
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1">
状态
</label>
<select <select
value={formData.status} value={formData.status}
onChange={(e) =>
setFormData({ ...formData, status: Number(e.target.value) })
}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
onChange={(e) => setFormData({ ...formData, status: Number(e.target.value) })}
className="w-[100%] border border-[#D9D9D9] rounded-md hover:border-blue-400 focus:border-blue-500 pt-[5px] pb-[5px] pl-[10px] text-[14px]"
> >
<option value={0}>启用</option> <option value={0}>启用</option>
<option value={1}>停用</option> <option value={1}>停用</option>
</select> </select>
</div>
</div>
<div className="flex w-[100%]">
{/* 保存按钮 */} {/* 保存按钮 */}
<CTAButton onClick={handleSubmit}>保存</CTAButton>
<CTAButton
onClick={handleSubmit}
className="w-[200px] mt-4 py-2.5 px-5 text-base font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors shadow-sm"
>
保存
</CTAButton>
{/* 取消按钮 */}
<CTAButton
onClick={handleCancel}
className="w-[200px] ml-[50px] mt-4 py-2.5 px-5 text-base font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors shadow-sm"
>
取消
</CTAButton>
</div>
</div> </div>
</div> </div>
); );
// (CSS)
// .form-input {
// @apply w-full px-3 py-2 border border-gray-300 rounded-md
// text-gray-700 text-sm placeholder-gray-400
// focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500
// transition-all;
// }
// 使 tailwind @apply
// .input-field {
// @apply w-full px-4 py-2.5 bg-theme-settings-input-bg border border-theme-border rounded-lg
// text-theme-text-primary text-sm placeholder-theme-settings-input-placeholder
// focus:ring-2 focus:ring-primary-500 focus:border-transparent
// transition-all outline-none;
// }
} }
function EditDepartmentModal({ dept, closeModal, onSuccess }) { function EditDepartmentModal({ dept, closeModal, onSuccess }) {

85
frontend/src/pages/Admin/Users/NewUserModal/index.jsx

@ -1,8 +1,9 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { X } from "@phosphor-icons/react"; import { X } from "@phosphor-icons/react";
import Admin from "@/models/admin"; import Admin from "@/models/admin";
import { userFromStorage } from "@/utils/request"; import { userFromStorage } from "@/utils/request";
import { MessageLimitInput, RoleHintDisplay } from ".."; import { MessageLimitInput, RoleHintDisplay } from "..";
import { Select } from "antd";
export default function NewUserModal({ closeModal }) { export default function NewUserModal({ closeModal }) {
const [error, setError] = useState(null); const [error, setError] = useState(null);
@ -11,6 +12,7 @@ export default function NewUserModal({ closeModal }) {
enabled: false, enabled: false,
limit: 10, limit: 10,
}); });
const [depId, setDepId] = useState([]);
const handleCreate = async (e) => { const handleCreate = async (e) => {
setError(null); setError(null);
@ -19,13 +21,36 @@ export default function NewUserModal({ closeModal }) {
const form = new FormData(e.target); const form = new FormData(e.target);
for (var [key, value] of form.entries()) data[key] = value; for (var [key, value] of form.entries()) data[key] = value;
data.dailyMessageLimit = messageLimit.enabled ? messageLimit.limit : null; data.dailyMessageLimit = messageLimit.enabled ? messageLimit.limit : null;
const { user, error } = await Admin.newUser(data);
if (!!user) window.location.reload();
console.log('用户', data);
const { user, error } = await Admin.newUserTo(data,depId);
// console.log('',user);
console.log('获取',depId);
// if (!!user) window.location.reload();
setError(error); setError(error);
}; };
const user = userFromStorage(); const user = userFromStorage();
const [departments, setDepartments] = useState([]);
const [treeData, setTreeData] = useState([]);
useEffect(() => {
async function fetchDepartments() {
const _departments = await Admin.depts();
const list = _departments.map(item=>({
value:item.deptId,
label:item.deptName
}))
console.log(222222, list);
setDepartments(list);
}
fetchDepartments();
}, []);
const handleChange = (value) => {
console.log(value);
setDepId(value)
};
return ( return (
<div className="fixed inset-0 z-50 overflow-auto bg-black bg-opacity-50 flex items-center justify-center"> <div className="fixed inset-0 z-50 overflow-auto bg-black bg-opacity-50 flex items-center justify-center">
@ -33,7 +58,7 @@ export default function NewUserModal({ closeModal }) {
<div className="relative p-6 border-b rounded-t border-theme-modal-border"> <div className="relative p-6 border-b rounded-t border-theme-modal-border">
<div className="w-full flex gap-x-2 items-center"> <div className="w-full flex gap-x-2 items-center">
<h3 className="text-xl font-semibold text-white overflow-hidden overflow-ellipsis whitespace-nowrap"> <h3 className="text-xl font-semibold text-white overflow-hidden overflow-ellipsis whitespace-nowrap">
Add user to instance
添加用户
</h3> </h3>
</div> </div>
<button <button
@ -52,27 +77,27 @@ export default function NewUserModal({ closeModal }) {
htmlFor="username" htmlFor="username"
className="block mb-2 text-sm font-medium text-white" className="block mb-2 text-sm font-medium text-white"
> >
Username
用户名
</label> </label>
<input <input
name="username" name="username"
type="text" type="text"
className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5" className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="User's username"
placeholder="请输入用户名"
minLength={2} minLength={2}
required={true} required={true}
autoComplete="off" autoComplete="off"
pattern="^[a-z0-9_-]+$" pattern="^[a-z0-9_-]+$"
onInvalid={(e) => onInvalid={(e) =>
e.target.setCustomValidity( e.target.setCustomValidity(
"Username must only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
"用户名只能包含小写字母、数字、“_”和“-”,不能有空格"
) )
} }
onChange={(e) => e.target.setCustomValidity("")} onChange={(e) => e.target.setCustomValidity("")}
/> />
<p className="mt-2 text-xs text-white/60"> <p className="mt-2 text-xs text-white/60">
Username must only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
用户名只能包含小写字母数字
下划线和连字符不带空格
</p> </p>
</div> </div>
<div> <div>
@ -80,27 +105,50 @@ export default function NewUserModal({ closeModal }) {
htmlFor="password" htmlFor="password"
className="block mb-2 text-sm font-medium text-white" className="block mb-2 text-sm font-medium text-white"
> >
Password
密码
</label> </label>
<input <input
name="password" name="password"
type="text" type="text"
className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5" className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="User's initial password"
placeholder="请输入密码"
required={true} required={true}
autoComplete="off" autoComplete="off"
minLength={8} minLength={8}
/> />
<p className="mt-2 text-xs text-white/60"> <p className="mt-2 text-xs text-white/60">
Password must be at least 8 characters long
密码长度至少为8个字符
</p> </p>
</div> </div>
<div>
<label
htmlFor="deptId"
className="block mb-2 text-sm font-medium text-white"
>
部门
</label>
<Select
className="w-[100%] h-[42px]"
showSearch
placeholder="请选择部门"
onChange={handleChange}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={departments}
/>
<p className="mt-2 text-xs text-white/60">
请选择部门
</p>
</div>
<div> <div>
<label <label
htmlFor="role" htmlFor="role"
className="block mb-2 text-sm font-medium text-white" className="block mb-2 text-sm font-medium text-white"
> >
Role
角色
</label> </label>
<select <select
name="role" name="role"
@ -117,6 +165,7 @@ export default function NewUserModal({ closeModal }) {
</select> </select>
<RoleHintDisplay role={role} /> <RoleHintDisplay role={role} />
</div> </div>
<MessageLimitInput <MessageLimitInput
role={role} role={role}
enabled={messageLimit.enabled} enabled={messageLimit.enabled}
@ -125,8 +174,8 @@ export default function NewUserModal({ closeModal }) {
/> />
{error && <p className="text-red-400 text-sm">Error: {error}</p>} {error && <p className="text-red-400 text-sm">Error: {error}</p>}
<p className="text-white text-xs md:text-sm"> <p className="text-white text-xs md:text-sm">
After creating a user they will need to login with their initial
login to get access.
创建用户后他们将需要登录他们的首字母
登录获取访问权限.
</p> </p>
</div> </div>
<div className="flex justify-between items-center mt-6 pt-6 border-t border-theme-modal-border"> <div className="flex justify-between items-center mt-6 pt-6 border-t border-theme-modal-border">
@ -135,13 +184,13 @@ export default function NewUserModal({ closeModal }) {
type="button" type="button"
className="transition-all duration-300 text-white hover:bg-zinc-700 px-4 py-2 rounded-lg text-sm" className="transition-all duration-300 text-white hover:bg-zinc-700 px-4 py-2 rounded-lg text-sm"
> >
Cancel
取消
</button> </button>
<button <button
type="submit" type="submit"
className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm" className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm"
> >
Add user
添加用户
</button> </button>
</div> </div>
</form> </form>

12
frontend/src/pages/Admin/Users/index.jsx

@ -112,8 +112,8 @@ function UsersContainer() {
const ROLE_HINT = { const ROLE_HINT = {
default: [ default: [
"Can only send chats with workspaces they are added to by admin or managers.",
"Cannot modify any settings at all.",
"只能发送由管理员或经理添加到的工作区的聊天记录吗.",
"不能修改任何设置.",
], ],
manager: [ manager: [
"Can view, create, and delete any workspaces and modify workspace-specific settings.", "Can view, create, and delete any workspaces and modify workspace-specific settings.",
@ -129,7 +129,7 @@ const ROLE_HINT = {
export function RoleHintDisplay({ role }) { export function RoleHintDisplay({ role }) {
return ( return (
<div className="flex flex-col gap-y-1 py-1 pb-4"> <div className="flex flex-col gap-y-1 py-1 pb-4">
<p className="text-sm font-medium text-theme-text-primary">Permissions</p>
<p className="text-sm font-medium text-theme-text-primary">权限</p>
<ul className="flex flex-col gap-y-1 list-disc px-4"> <ul className="flex flex-col gap-y-1 list-disc px-4">
{ROLE_HINT[role ?? "default"].map((hints, i) => { {ROLE_HINT[role ?? "default"].map((hints, i) => {
return ( return (
@ -150,7 +150,7 @@ export function MessageLimitInput({ enabled, limit, updateState, role }) {
<div className="flex flex-col gap-y-1"> <div className="flex flex-col gap-y-1">
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
<h2 className="text-base leading-6 font-bold text-white"> <h2 className="text-base leading-6 font-bold text-white">
Limit messages per day
限制每天发送的信息
</h2> </h2>
<label className="relative inline-flex cursor-pointer items-center"> <label className="relative inline-flex cursor-pointer items-center">
<input <input
@ -168,8 +168,8 @@ export function MessageLimitInput({ enabled, limit, updateState, role }) {
</label> </label>
</div> </div>
<p className="text-xs leading-[18px] font-base text-white/60"> <p className="text-xs leading-[18px] font-base text-white/60">
Restrict this user to a number of successful queries or chats within a
24 hour window.
将此用户限制为只能进行多个成功的查询或聊天
24小时窗口
</p> </p>
</div> </div>
{enabled && ( {enabled && (

6
frontend/src/pages/DataAnalysis/DataAnalysis.css

@ -13,12 +13,16 @@
grid-template-rows: 100px 1fr; grid-template-rows: 100px 1fr;
} }
.head{
position: relative;
}
.head>div:first-child img { .head>div:first-child img {
width: 35px; width: 35px;
height: 35px; height: 35px;
position: absolute; position: absolute;
top: 25px; top: 25px;
left: 140px;
left: 0;
cursor: pointer; cursor: pointer;
} }

7
frontend/src/pages/DataAnalysis/index.jsx

@ -1,4 +1,5 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import './DataAnalysis.css' import './DataAnalysis.css'
import sou from './img/sou.png' import sou from './img/sou.png'
import home from './img/home.png' import home from './img/home.png'
@ -16,7 +17,7 @@ import { message } from "antd";
function DataAnalysis() { function DataAnalysis() {
const [renderKey, setRenderKey] = useState(); const [renderKey, setRenderKey] = useState();
const navigate = useNavigate();
const list = [ const list = [
{ {
name: '舆情分析', name: '舆情分析',
@ -78,7 +79,7 @@ function DataAnalysis() {
const bindUrl = (e) => { const bindUrl = (e) => {
console.log(1234, e); console.log(1234, e);
if (e.url) { if (e.url) {
window.location = e.url
navigate(e.url)
} else { } else {
message.info({ message.info({
content: e.name + '开发中...' content: e.name + '开发中...'
@ -88,7 +89,7 @@ function DataAnalysis() {
const bindUrl1 = () => { const bindUrl1 = () => {
window.location = "/"
navigate("/")
} }
return ( return (
<div className='box'> <div className='box'>

10
frontend/src/pages/Home/home.css

@ -1,7 +1,7 @@
.box {
.bod_box {
width: 100%; width: 100%;
} }
.box video {
.bod_box video {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -69,11 +69,11 @@
.head2 div:nth-child(2) { .head2 div:nth-child(2) {
margin: 0 20px; margin: 0 20px;
margin-top: 10px;
margin-top: 14px;
} }
.head2 div:nth-child(3) { .head2 div:nth-child(3) {
margin-top: 10px;
margin-top: 14px;
} }
@ -82,7 +82,7 @@
background-size: 100% 100%; background-size: 100% 100%;
} }
.content {
.matter {
width: 100%; width: 100%;
top: 0; top: 0;
bottom: 0; bottom: 0;

40
frontend/src/pages/Home/index.jsx

@ -1,4 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useNavigate } from 'react-router-dom';
import './home.css' import './home.css'
import videoRef from "./img/bj1.mp4" import videoRef from "./img/bj1.mp4"
import headImg from "./img/head.png" import headImg from "./img/head.png"
@ -14,10 +15,11 @@ import icon7 from "./img/7.png"
import icon8 from "./img/8.png" import icon8 from "./img/8.png"
export default function Home() { export default function Home() {
const [data, setData] = useState(false);
const weeks = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const [renderKey, setRenderKey] = useState(1);
const WeekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const [currentTime, setCurrentTime] = useState(moment());
const navigate = useNavigate();
// 1- 2- 3- 4- // 1- 2- 3- 4-
const list = [ const list = [
{ {
@ -70,29 +72,37 @@ export default function Home() {
}, },
] ]
// //
const bindUrl = (e) => { const bindUrl = (e) => {
console.log(1234, e); console.log(1234, e);
if (e.type == 1) { if (e.type == 1) {
window.location = e.url
// window.location = e.url
navigate(e.url)
} else { } else {
message.info({
content: e.name + '开发中...'
})
message.info(`${e.name}功能开发中,敬请期待`)
} }
} }
//
//
useEffect(() => { useEffect(() => {
const timer = setInterval(() => { const timer = setInterval(() => {
setRenderKey(Math.random());
setCurrentTime(moment());
}, 1000); }, 1000);
//
return () => clearInterval(timer); return () => clearInterval(timer);
}, []); }, []);
//
const formatTime = (time) => ({
time: time.format('HH:mm:ss'),
date: time.format('YYYY年MM月DD日'),
week: WeekDays[time.day()]
});
const { time, date, week } = formatTime(currentTime);
return ( return (
<div className='box'>
<div className='bod_box'>
{/* 背景视频 */} {/* 背景视频 */}
<video autoPlay loop muted> <video autoPlay loop muted>
<source src={videoRef} type="video/mp4"></source> <source src={videoRef} type="video/mp4"></source>
@ -102,12 +112,12 @@ export default function Home() {
<div className="head1_1">阿拉善盟AI行政数据分析与决策参考系统</div> <div className="head1_1">阿拉善盟AI行政数据分析与决策参考系统</div>
<img src={headImg} alt="" /> <img src={headImg} alt="" />
<div className="head2"> <div className="head2">
<div>{moment().format('HH:mm:ss')}</div>
<div>{moment().format('YYYY年MM月DD日')} </div>
<div>{weeks[moment().day()]}</div>
<div>{time}</div>
<div>{date} </div>
<div>{week}</div>
</div> </div>
</div> </div>
<div className="content">
<div className="matter">
<Carousel draggable> <Carousel draggable>
<div className="lunType"> <div className="lunType">
<div className="lunType1_1"> <div className="lunType1_1">

30
frontend/src/pages/ReportGeneration/ReportGeneration.css

@ -12,12 +12,17 @@
display: grid; display: grid;
grid-template-rows: 100px 1fr; grid-template-rows: 100px 1fr;
} }
.head{
position: relative;
}
.head>div:first-child img { .head>div:first-child img {
width: 35px; width: 35px;
height: 35px; height: 35px;
position: absolute; position: absolute;
top: 25px; top: 25px;
left: 140px;
left: 0;
cursor: pointer; cursor: pointer;
} }
@ -75,35 +80,47 @@
} }
.content2 { .content2 {
width: 100%;
display: grid; display: grid;
grid-template-rows: 1fr 50px; grid-template-rows: 1fr 50px;
box-shadow: 0 0 2px #CFCFCF; box-shadow: 0 0 2px #CFCFCF;
background-color: #fff; background-color: #fff;
border-radius: 10px; border-radius: 10px;
padding: 20px 15px;
} }
.content2_1 { .content2_1 {
width: 95%;
display: grid;
grid-template-columns: 50px 1fr;
width: 100%;
display: flex;
column-gap: 20px; column-gap: 20px;
border-bottom: 1px solid #F0F0F5; border-bottom: 1px solid #F0F0F5;
padding: 10px;
} }
.nr1 img { .nr1 img {
width: 100%; width: 100%;
} }
.nr2 {
width: 100%;
}
.nr2 div:first-child { .nr2 div:first-child {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
} }
.nr2 div:last-child { .nr2 div:last-child {
width: 100%;
height: 60px;
color: #7E807C; color: #7E807C;
font-size: 14px; font-size: 14px;
padding: 5px 0;
margin: 5px 0 20px;
overflow: hidden;
display: -webkit-box;
box-sizing: border-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
} }
.content2_2 { .content2_2 {
@ -120,4 +137,3 @@
border-radius: 5px; border-radius: 5px;
font-size: 14px; font-size: 14px;
} }

29
frontend/src/pages/Tendency/Tendency.css

@ -12,12 +12,16 @@
display: grid; display: grid;
grid-template-rows: 100px 1fr; grid-template-rows: 100px 1fr;
} }
.head{
position: relative;
}
.head>div:first-child img { .head>div:first-child img {
width: 35px; width: 35px;
height: 35px; height: 35px;
position: absolute; position: absolute;
top: 25px; top: 25px;
left: 140px;
left: 0;
cursor: pointer; cursor: pointer;
} }
@ -75,35 +79,47 @@
} }
.content2 { .content2 {
width: 100%;
display: grid; display: grid;
grid-template-rows: 1fr 50px; grid-template-rows: 1fr 50px;
box-shadow: 0 0 2px #CFCFCF; box-shadow: 0 0 2px #CFCFCF;
background-color: #fff; background-color: #fff;
border-radius: 10px; border-radius: 10px;
padding: 20px 15px;
} }
.content2_1 { .content2_1 {
width: 95%;
display: grid;
grid-template-columns: 50px 1fr;
width: 100%;
display: flex;
column-gap: 20px; column-gap: 20px;
border-bottom: 1px solid #F0F0F5; border-bottom: 1px solid #F0F0F5;
padding: 10px;
} }
.nr1 img { .nr1 img {
width: 100%; width: 100%;
} }
.nr2 {
width: 100%;
}
.nr2 div:first-child { .nr2 div:first-child {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
} }
.nr2 div:last-child { .nr2 div:last-child {
width: 100%;
height: 60px;
color: #7E807C; color: #7E807C;
font-size: 14px; font-size: 14px;
padding: 5px 0;
margin: 5px 0 20px;
overflow: hidden;
display: -webkit-box;
box-sizing: border-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
} }
.content2_2 { .content2_2 {
@ -120,4 +136,3 @@
border-radius: 5px; border-radius: 5px;
font-size: 14px; font-size: 14px;
} }

3
frontend/src/utils/constants.js

@ -1,4 +1,5 @@
export const API_BASE = import.meta.env.VITE_API_BASE || "/api";
// export const API_BASE = import.meta.env.VITE_API_BASE || "/api";
export const API_BASE = 'http://172.16.2.31:3001/api'
export const ONBOARDING_SURVEY_URL = "https://onboarding.anythingllm.com"; export const ONBOARDING_SURVEY_URL = "https://onboarding.anythingllm.com";
export const AUTH_USER = "anythingllm_user"; export const AUTH_USER = "anythingllm_user";

Loading…
Cancel
Save