Browse Source

部门管理-用户管理

master
談蓝色 10 months ago
parent
commit
8142c9c264
  1. 1
      frontend/.env.example
  2. 16
      frontend/src/models/admin.js
  3. 194
      frontend/src/pages/Admin/Section/index.jsx
  4. 85
      frontend/src/pages/Admin/Users/NewUserModal/index.jsx
  5. 20
      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. 34
      frontend/src/pages/ReportGeneration/ReportGeneration.css
  11. 33
      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://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='/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 [];
});
},
// 旧用户
newUser: async (data) => {
return await fetch(`${API_BASE}/admin/users/new`, {
method: "POST",
@ -27,6 +28,21 @@ const Admin = {
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) => {
return await fetch(`${API_BASE}/admin/user/${userId}`, {
method: "POST",

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

@ -61,7 +61,7 @@ function DepartmentsContainer() {
useEffect(() => {
async function fetchDepartments() {
const _departments = await Admin.depts();
console.log(1111,_departments);
console.log(1111, _departments);
setDepartments(buildTree(_departments)); //
setLoading(false);
}
@ -85,28 +85,28 @@ function DepartmentsContainer() {
return (
<table className="w-full text-sm text-left rounded-lg min-w-[640px] border-spacing-0">
<thead className="text-theme-text-secondary text-xs leading-[18px] font-bold uppercase border-white/10 border-b">
<tr>
<th scope="col" className="px-6 py-3 rounded-tl-lg">
组织机构名称
</th>
<th scope="col" className="px-6 py-3">
排序
</th>
<th scope="col" className="px-6 py-3">
状态
</th>
<th scope="col" className="px-6 py-3">
创建时间
</th>
<th scope="col" className="px-6 py-3 rounded-tr-lg">
操作
</th>
</tr>
<tr>
<th scope="col" className="px-6 py-3 rounded-tl-lg">
组织机构名称
</th>
<th scope="col" className="px-6 py-3">
排序
</th>
<th scope="col" className="px-6 py-3">
状态
</th>
<th scope="col" className="px-6 py-3">
创建时间
</th>
<th scope="col" className="px-6 py-3 rounded-tr-lg">
操作
</th>
</tr>
</thead>
<tbody>
{departments.map((dept) => (
<DepartmentRow key={dept.deptId} dept={dept} />
))}
{departments.map((dept) => (
<DepartmentRow key={dept.deptId} dept={dept} />
))}
</tbody>
</table>
);
@ -160,11 +160,10 @@ function DepartmentRow({ dept }) {
<td className="px-6 py-4 text-theme-text-secondary">{dept.orderNum}</td>
<td className="px-6 py-4">
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${
dept.status === 0
? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800"
}`}
className={`px-2 py-1 rounded-full text-xs font-medium ${dept.status === 0
? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800"
}`}
>
{dept.status === 0 ? "启用" : "停用"}
</span>
@ -239,71 +238,122 @@ function NewDepartmentModal({ closeModal }) {
//
const handleSubmit = async () => {
await Admin.addDepts(formData);
closeModal()
window.location.reload();
};
//
const handleCancel = () => {
closeModal();
};
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>
<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>
<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="请选择上级组织机构"
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>
{/* 组织机构名称输入框 */}
<input
type="text"
placeholder="组织机构名称"
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"
/>
{/* 输入框组 */}
<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
type="text"
placeholder="请输入名称"
value={formData.deptName}
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>
{/* 排序输入框 */}
<input
type="number"
placeholder="排序"
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"
/>
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1">
排序
</label>
<input
type="number"
placeholder="请输入排序号"
value={formData.orderNum}
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>
{/* 状态选择器 */}
<select
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"
>
<option value={0}>启用</option>
<option value={1}>停用</option>
</select>
<div className="space-y-1">
<label className="text-sm font-medium text-gray-600 block mb-1">
状态
</label>
<select
value={formData.status}
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={1}>停用</option>
</select>
</div>
</div>
{/* 保存按钮 */}
<CTAButton onClick={handleSubmit}>保存</CTAButton>
<div className="flex w-[100%]">
{/* 保存按钮 */}
<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>
);
// (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 }) {
@ -327,7 +377,7 @@ function EditDepartmentModal({ dept, closeModal, onSuccess }) {
}, []);
const handleSubmit = async () => {
await Admin.updateDept(dept.deptId,formData); // API
await Admin.updateDept(dept.deptId, formData); // API
onSuccess(); //
closeModal();
};

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 Admin from "@/models/admin";
import { userFromStorage } from "@/utils/request";
import { MessageLimitInput, RoleHintDisplay } from "..";
import { Select } from "antd";
export default function NewUserModal({ closeModal }) {
const [error, setError] = useState(null);
@ -11,6 +12,7 @@ export default function NewUserModal({ closeModal }) {
enabled: false,
limit: 10,
});
const [depId, setDepId] = useState([]);
const handleCreate = async (e) => {
setError(null);
@ -19,13 +21,36 @@ export default function NewUserModal({ closeModal }) {
const form = new FormData(e.target);
for (var [key, value] of form.entries()) data[key] = value;
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);
};
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 (
<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="w-full flex gap-x-2 items-center">
<h3 className="text-xl font-semibold text-white overflow-hidden overflow-ellipsis whitespace-nowrap">
Add user to instance
添加用户
</h3>
</div>
<button
@ -52,27 +77,27 @@ export default function NewUserModal({ closeModal }) {
htmlFor="username"
className="block mb-2 text-sm font-medium text-white"
>
Username
用户名
</label>
<input
name="username"
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"
placeholder="User's username"
placeholder="请输入用户名"
minLength={2}
required={true}
autoComplete="off"
pattern="^[a-z0-9_-]+$"
onInvalid={(e) =>
e.target.setCustomValidity(
"Username must only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
"用户名只能包含小写字母、数字、“_”和“-”,不能有空格"
)
}
onChange={(e) => e.target.setCustomValidity("")}
/>
<p className="mt-2 text-xs text-white/60">
Username must only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
用户名只能包含小写字母数字
下划线和连字符不带空格
</p>
</div>
<div>
@ -80,27 +105,50 @@ export default function NewUserModal({ closeModal }) {
htmlFor="password"
className="block mb-2 text-sm font-medium text-white"
>
Password
密码
</label>
<input
name="password"
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"
placeholder="User's initial password"
placeholder="请输入密码"
required={true}
autoComplete="off"
minLength={8}
/>
<p className="mt-2 text-xs text-white/60">
Password must be at least 8 characters long
密码长度至少为8个字符
</p>
</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>
<label
htmlFor="role"
className="block mb-2 text-sm font-medium text-white"
>
Role
角色
</label>
<select
name="role"
@ -117,6 +165,7 @@ export default function NewUserModal({ closeModal }) {
</select>
<RoleHintDisplay role={role} />
</div>
<MessageLimitInput
role={role}
enabled={messageLimit.enabled}
@ -125,8 +174,8 @@ export default function NewUserModal({ closeModal }) {
/>
{error && <p className="text-red-400 text-sm">Error: {error}</p>}
<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>
</div>
<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"
className="transition-all duration-300 text-white hover:bg-zinc-700 px-4 py-2 rounded-lg text-sm"
>
Cancel
取消
</button>
<button
type="submit"
className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm"
>
Add user
添加用户
</button>
</div>
</form>

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

@ -62,7 +62,7 @@ function UsersContainer() {
useEffect(() => {
async function fetchUsers() {
const _users = await Admin.users();
console.log(1111,_users);
console.log(1111, _users);
setUsers(_users);
setLoading(false);
}
@ -88,13 +88,13 @@ function UsersContainer() {
<thead className="text-theme-text-secondary text-xs leading-[18px] font-bold uppercase border-white/10 border-b">
<tr>
<th scope="col" className="px-6 py-3 rounded-tl-lg">
用户名
用户名
</th>
<th scope="col" className="px-6 py-3">
角色
角色
</th>
<th scope="col" className="px-6 py-3">
添加日期
添加日期
</th>
<th scope="col" className="px-6 py-3 rounded-tr-lg">
{" "}
@ -112,8 +112,8 @@ function UsersContainer() {
const ROLE_HINT = {
default: [
"Can only send chats with workspaces they are added to by admin or managers.",
"Cannot modify any settings at all.",
"只能发送由管理员或经理添加到的工作区的聊天记录吗.",
"不能修改任何设置.",
],
manager: [
"Can view, create, and delete any workspaces and modify workspace-specific settings.",
@ -129,7 +129,7 @@ const ROLE_HINT = {
export function RoleHintDisplay({ role }) {
return (
<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">
{ROLE_HINT[role ?? "default"].map((hints, i) => {
return (
@ -150,7 +150,7 @@ export function MessageLimitInput({ enabled, limit, updateState, role }) {
<div className="flex flex-col gap-y-1">
<div className="flex items-center gap-x-2">
<h2 className="text-base leading-6 font-bold text-white">
Limit messages per day
限制每天发送的信息
</h2>
<label className="relative inline-flex cursor-pointer items-center">
<input
@ -168,8 +168,8 @@ export function MessageLimitInput({ enabled, limit, updateState, role }) {
</label>
</div>
<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>
</div>
{enabled && (

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

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

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

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

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

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

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

@ -1,4 +1,5 @@
import { useState, useEffect } from "react";
import { useNavigate } from 'react-router-dom';
import './home.css'
import videoRef from "./img/bj1.mp4"
import headImg from "./img/head.png"
@ -14,10 +15,11 @@ import icon7 from "./img/7.png"
import icon8 from "./img/8.png"
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-
const list = [
{
@ -70,29 +72,37 @@ export default function Home() {
},
]
//
const bindUrl = (e) => {
console.log(1234, e);
if (e.type == 1) {
window.location = e.url
// window.location = e.url
navigate(e.url)
} else {
message.info({
content: e.name + '开发中...'
})
message.info(`${e.name}功能开发中,敬请期待`)
}
}
//
//
useEffect(() => {
const timer = setInterval(() => {
setRenderKey(Math.random());
setCurrentTime(moment());
}, 1000);
//
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 (
<div className='box'>
<div className='bod_box'>
{/* 背景视频 */}
<video autoPlay loop muted>
<source src={videoRef} type="video/mp4"></source>
@ -102,12 +112,12 @@ export default function Home() {
<div className="head1_1">阿拉善盟AI行政数据分析与决策参考系统</div>
<img src={headImg} alt="" />
<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 className="content">
<div className="matter">
<Carousel draggable>
<div className="lunType">
<div className="lunType1_1">

34
frontend/src/pages/ReportGeneration/ReportGeneration.css

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

33
frontend/src/pages/Tendency/Tendency.css

@ -12,12 +12,16 @@
display: grid;
grid-template-rows: 100px 1fr;
}
.head>div:first-child img{
.head{
position: relative;
}
.head>div:first-child img {
width: 35px;
height: 35px;
position: absolute;
top: 25px;
left: 140px;
left: 0;
cursor: pointer;
}
@ -75,35 +79,47 @@
}
.content2 {
width: 100%;
display: grid;
grid-template-rows: 1fr 50px;
box-shadow: 0 0 2px #CFCFCF;
background-color: #fff;
border-radius: 10px;
padding: 20px 15px;
}
.content2_1 {
width: 95%;
display: grid;
grid-template-columns: 50px 1fr;
width: 100%;
display: flex;
column-gap: 20px;
border-bottom: 1px solid #F0F0F5;
padding: 10px;
}
.nr1 img {
width: 100%;
}
.nr2 {
width: 100%;
}
.nr2 div:first-child {
font-size: 18px;
font-weight: bold;
}
.nr2 div:last-child {
width: 100%;
height: 60px;
color: #7E807C;
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 {
@ -119,5 +135,4 @@
margin-right: 20px;
border-radius: 5px;
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 AUTH_USER = "anythingllm_user";

Loading…
Cancel
Save