This commit is contained in:
oneao committed 2025-12-17 17:28:57 +08:00
1 parent 7cd7bbd166
commit ff327ba2fd
47 files changed
+4362 -1230

No files matched your search

@@ -23,7 +23,7 @@ public class AuthRegisterDTO {
@NotBlank(message = "所属行业不能为空")
private String industry;
@NotBlank(message = "公司地址不能为空")
private String address;
private String area;
private String phone;
private String email;
private String profile;
@@ -61,7 +61,7 @@ public class AuthIdentityService {
.setId(companyId)
.setName(company.getName())
.setIndustry(company.getIndustry())
.setAddress(company.getAddress())
.setArea(company.getArea())
.setPhone(company.getPhone())
.setEmail(company.getEmail())
.setProfile(company.getProfile())
@@ -0,0 +1,40 @@
package cn.link56.base.controller;
import cn.link56.base.model.dto.AddFileDTO;
import cn.link56.base.model.vo.AliyunKeyVO;
import cn.link56.base.service.FileService;
import cn.link56.common.Result;
import cn.link56.common.utils.HttpUtils;
import cn.link56.common.utils.JsonUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/base/file")
public class FileController {
@Resource
private FileService fileService;
@PostMapping("/getAliyunKey")
public Result<AliyunKeyVO> getAliyunKey() {
String requestUrl = "http://g3oss.g3soft.cn:8082/upload?orgid=link56&bucket=g3hdzjsj";
String s = HttpUtils.sendGet(requestUrl);
AliyunKeyVO aliyunKeyVO = (AliyunKeyVO) JsonUtils.toBean(s, AliyunKeyVO.class);
assert aliyunKeyVO != null;
return Result.success(aliyunKeyVO);
}
@PostMapping("/add")
public Result<Void> insertFile(@RequestBody @Validated AddFileDTO addFileDTO) {
fileService.addFile(addFileDTO);
return Result.success();
}
}
@@ -0,0 +1,9 @@
package cn.link56.base.mapper;
import cn.link56.base.model.po.FilePO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface FileMapper extends BaseMapper<FilePO> {
}
@@ -0,0 +1,27 @@
package cn.link56.base.model.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AddFileDTO {
@NotBlank(
message = "文件名称不能为空"
)
private String fileName;
@NotBlank(
message = "文件大小不能为空"
)
private String fileSize;
@NotBlank(
message = "文件全路径oss不能为空"
)
private String fileMapName;
}
@@ -0,0 +1,41 @@
package cn.link56.base.model.po;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("b_file")
@Accessors(chain = true)
public class FilePO {
@TableId(value = "b_id")
private String id;
@TableField("mx_filename")
private String name;
@TableField("mx_filesize")
private String size;
@TableField("mx_fileext")
private String ext;
@TableField("mx_mapfilename")
private String mapName;
@TableField(
value = "b_create_time",
fill = FieldFill.INSERT
)
private String createTime;
@TableField(
value = "b_create_by",
fill = FieldFill.INSERT
)
private String createBy;
}
@@ -0,0 +1,18 @@
package cn.link56.base.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AliyunKeyVO {
private String accessid;
private String policy;
private String signature;
private String dir;
private String host;
private String expire;
private String callback;
}
@@ -0,0 +1,37 @@
package cn.link56.base.service;
import cn.link56.base.mapper.FileMapper;
import cn.link56.base.model.dto.AddFileDTO;
import cn.link56.base.model.po.FilePO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
public class FileService extends ServiceImpl<FileMapper, FilePO> {
@Resource
private FileMapper fileMapper;
@Transactional
public void addFile(AddFileDTO addFileDTO){
String fileName = addFileDTO.getFileName();
String fileSize = addFileDTO.getFileSize();
String fileMapName = addFileDTO.getFileMapName();
String suffix = "";
if (StringUtils.isNotEmpty(fileName)) {
int lastDotIndex = fileName.lastIndexOf(46);
if (lastDotIndex != -1 && lastDotIndex < fileName.length() - 1) {
suffix = fileName.substring(lastDotIndex + 1);
}
}
FilePO filePO = new FilePO();
filePO.setExt(suffix).setName(fileName).setMapName(fileMapName).setSize(fileSize);
fileMapper.insert(filePO);
}
}
@@ -0,0 +1,19 @@
package cn.link56.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
public class BasePageVO<T> {
private long total;
private List<T> records;
}
@@ -19,8 +19,8 @@ public class WebMvcConfig implements WebMvcConfigurer {
.addPathPatterns("/**")
.excludePathPatterns(
"/auth/**",
"/company/getCompanyPage",
"/company/getPublicDetail",
"/company/query",
"/company/detail/**",
"/company/recommend",
"/company/recommend/hot",
@@ -0,0 +1,197 @@
package cn.link56.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.net.ssl.*;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
@Slf4j
public class HttpUtils {
public static String sendGet(String url) {
return sendGet(url, "");
}
public static String sendGet(String url, String param) {
return sendGet(url, param, "UTF-8");
}
public static String sendGet(String url, String param, String contentType) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line;
while((line = in.readLine()) != null) {
result.append(line);
}
} catch (ConnectException e) {
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
public static String sendPost(String url, String param) {
return sendPost(url, param, "application/x-www-form-urlencoded");
}
public static String sendPost(String url, String param, String contentType) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
log.info("sendPost - {}", url);
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line;
while((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
public static String sendSSLPost(String url, String param) {
return sendSSLPost(url, param, "application/x-www-form-urlencoded");
}
public static String sendSSLPost(String url, String param, String contentType) {
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try {
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init((KeyManager[])null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection)console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while((ret = br.readLine()) != null) {
if (ret != null && !"".equals(ret.trim())) {
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
} catch (ConnectException e) {
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}
private static class TrustAnyTrustManager implements X509TrustManager {
private TrustAnyTrustManager() {
}
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
private TrustAnyHostnameVerifier() {
}
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}
@@ -1,12 +1,16 @@
package cn.link56.company.controller;
import cn.link56.common.BasePageVO;
import cn.link56.common.Result;
import cn.link56.company.model.dto.PageCompanyDTO;
import cn.link56.company.model.vo.CompanyDetailVO;
import cn.link56.company.model.vo.PageCompanyVO;
import cn.link56.company.model.vo.RecommendCompanyVO;
import cn.link56.company.model.vo.RecommendHotCompanyVO;
import cn.link56.company.service.CompanyService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@@ -17,15 +21,32 @@ public class CompanyController {
@Resource
private CompanyService companyService;
// 公司分页
@PostMapping("/query")
public Result<BasePageVO<PageCompanyVO>> query(@RequestBody PageCompanyDTO pageCompanyDTO){
BasePageVO<PageCompanyVO> data = companyService.queryCompany(pageCompanyDTO);
return Result.success(data);
}
// 企业名录
@GetMapping("/recommend")
public Result<List<RecommendCompanyVO>> listRecommend(){
List<RecommendCompanyVO> list = companyService.listRecommend();
return Result.success(list);
}
// 热门推荐
@GetMapping("/recommend/hot")
public Result<List<RecommendHotCompanyVO>> listHot(){
List<RecommendHotCompanyVO> list = companyService.listHot();
return Result.success(list);
}
// 公司详细
@GetMapping("/detail/{id}")
public Result<CompanyDetailVO> getCompanyDetail(@PathVariable Long id){
CompanyDetailVO companyDetailVO = companyService.getCompanyDetail(id);
return Result.success(companyDetailVO);
}
}
@@ -0,0 +1,19 @@
package cn.link56.company.model.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageCompanyDTO {
private Integer currentPage;
private Integer pageSize;
private List<String> areas;
private List<String> industries;
private String name;
}
@@ -30,8 +30,8 @@ public class CompanyPO {
@TableField("b_phone")
private String phone;
@TableField("b_address")
private String address;
@TableField("b_area")
private String area;
@TableField("b_industry")
private String industry;
@@ -0,0 +1,37 @@
package cn.link56.company.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CompanyDetailVO {
private Long id;
private String name;
private List<String> areas;
private List<String> industries;
private String logo;
private String profile;
private String email;
private String phone;
private String description;
private List<User> users;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class User{
private Long id;
private Long companyId;
private String email;
private String phone;
private Integer role;
private String position;
private String name;
}
}
@@ -0,0 +1,23 @@
package cn.link56.company.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class PageCompanyVO {
private Long id;
private String name;
private List<String> areas;
private List<String> industries;
private String logo;
private String profile;
private String phone;
private String email;
}
@@ -1,15 +1,26 @@
package cn.link56.company.service;
import cn.link56.common.BasePageVO;
import cn.link56.company.mapper.CompanyMapper;
import cn.link56.company.mapper.CompanyUserMapper;
import cn.link56.company.model.dto.PageCompanyDTO;
import cn.link56.company.model.middle.RecommendCompanyRow;
import cn.link56.company.model.po.CompanyPO;
import cn.link56.company.model.po.CompanyUserPO;
import cn.link56.company.model.vo.CompanyDetailVO;
import cn.link56.company.model.vo.PageCompanyVO;
import cn.link56.company.model.vo.RecommendCompanyVO;
import cn.link56.company.model.vo.RecommendHotCompanyVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -17,6 +28,8 @@ import java.util.stream.Collectors;
public class CompanyService extends ServiceImpl<CompanyMapper,CompanyPO> {
@Resource
private CompanyMapper companyMapper;
@Resource
private CompanyUserService companyUserService;
public List<RecommendCompanyVO> listRecommend() {
List<RecommendCompanyRow> rows = companyMapper.listRecommend();
@@ -86,4 +99,84 @@ public class CompanyService extends ServiceImpl<CompanyMapper,CompanyPO> {
return count > 0;
}
public BasePageVO<PageCompanyVO> queryCompany(PageCompanyDTO pageCompanyDTO) {
Integer currentPage = pageCompanyDTO.getCurrentPage();
Integer pageSize = pageCompanyDTO.getPageSize();
String name = pageCompanyDTO.getName();
List<String> areas = pageCompanyDTO.getAreas();
List<String> industries = pageCompanyDTO.getIndustries();
// 分页
Page<CompanyPO> companyPage = new Page<>(currentPage,pageSize);
LambdaQueryWrapper<CompanyPO> queryWrapper = new LambdaQueryWrapper<>();
// 名称
if (StringUtils.isNotBlank(name)){
queryWrapper.like(CompanyPO::getName,name);
}
// 地区
if (areas != null && !areas.isEmpty()){
queryWrapper.and(wrapper -> {
for (String area : areas) {
wrapper.or(w -> w.like(CompanyPO::getArea, area));
}
});
}
// 行业
if (industries != null && !industries.isEmpty()) {
queryWrapper.and(wrapper -> {
for (String industry : industries) {
wrapper.or(w -> w.like(CompanyPO::getIndustry, industry));
}
});
}
queryWrapper.eq(CompanyPO::getCanuse,"1");
List<PageCompanyVO> result = companyMapper.selectList(companyPage, queryWrapper).stream().map(item -> {
PageCompanyVO pageCompanyVO = new PageCompanyVO();
pageCompanyVO.setId(item.getId());
pageCompanyVO.setName(item.getName());
pageCompanyVO.setProfile(item.getProfile());
pageCompanyVO.setLogo(item.getLogo());
pageCompanyVO.setAreas(Arrays.stream(item.getArea().split(","))
.collect(Collectors.toList()));
pageCompanyVO.setIndustries(Arrays.stream(item.getIndustry().split(","))
.collect(Collectors.toList()));
return pageCompanyVO;
}).collect(Collectors.toList());
return new BasePageVO<PageCompanyVO>()
.setRecords(result)
.setTotal(companyPage.getTotal());
}
public CompanyDetailVO getCompanyDetail(Long companyId) {
CompanyPO companyPO = companyMapper.selectById(companyId);
List<CompanyUserPO> companyUserPOS = companyUserService.listByCompanyId(companyId);
CompanyDetailVO companyDetailVO = new CompanyDetailVO();
BeanUtils.copyProperties(companyPO,companyDetailVO);
companyDetailVO.setAreas(Arrays.stream(companyPO.getArea().split(","))
.collect(Collectors.toList()));
companyDetailVO.setIndustries(Arrays.stream(companyPO.getIndustry().split(","))
.collect(Collectors.toList()));
companyDetailVO.setUsers(companyUserPOS.stream()
.map(item -> {
CompanyDetailVO.User user = new CompanyDetailVO.User();
BeanUtils.copyProperties(item, user); // 复制属性
return user;
})
.collect(Collectors.toList()));
return companyDetailVO;
}
}
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class CompanyUserService extends ServiceImpl<CompanyUserMapper, CompanyUserPO> {
@@ -56,4 +57,10 @@ public class CompanyUserService extends ServiceImpl<CompanyUserMapper, CompanyUs
return companyUserMapper.selectOne(queryWrapper);
}
public List<CompanyUserPO> listByCompanyId(Long companyId){
LambdaQueryWrapper<CompanyUserPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CompanyUserPO::getCompanyId,companyId);
return companyUserMapper.selectList(queryWrapper);
}
}
@@ -19,7 +19,7 @@
LEFT JOIN b_company c
ON c.b_canuse = '1'
AND c.b_recommend = '1'
AND c.b_address LIKE '%' + shi.b_name + '%'
AND c.b_area LIKE '%' + shi.b_name + '%'
WHERE
shi.b_canuse = '1'
@@ -12,6 +12,8 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^1.13.2",
"dayjs": "^1.11.19",
"element-plus": "^2.12.0",
+488
View File
@@ -11,6 +11,12 @@ importers:
'@element-plus/icons-vue':
specifier: ^2.3.2
version: 2.3.2(vue@3.5.25(typescript@5.9.3))
'@wangeditor/editor':
specifier: ^5.1.23
version: 5.1.23
'@wangeditor/editor-for-vue':
specifier: ^5.1.12
version: 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.25(typescript@5.9.3))
axios:
specifier: ^1.13.2
version: 1.13.2
@@ -149,6 +155,10 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
'@babel/runtime@7.28.4':
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
@@ -686,12 +696,18 @@ packages:
'@sxzz/popperjs-es@2.11.7':
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
'@transloadit/prettier-bytes@0.0.7':
resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/event-emitter@0.3.5':
resolution: {integrity: sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -775,6 +791,23 @@ packages:
resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@uppy/companion-client@2.2.2':
resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
'@uppy/core@2.3.4':
resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
'@uppy/store-default@2.1.1':
resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
'@uppy/utils@4.1.3':
resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
'@uppy/xhr-upload@2.1.3':
resolution: {integrity: sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==}
peerDependencies:
'@uppy/core': ^2.3.3
'@vitejs/plugin-vue@6.0.2':
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -873,6 +906,93 @@ packages:
'@vueuse/shared@9.13.0':
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
'@wangeditor/basic-modules@1.1.7':
resolution: {integrity: sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==}
peerDependencies:
'@wangeditor/core': 1.x
dom7: ^3.0.0
lodash.throttle: ^4.1.1
nanoid: ^3.2.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/code-highlight@1.0.3':
resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
peerDependencies:
'@wangeditor/core': 1.x
dom7: ^3.0.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/core@1.1.19':
resolution: {integrity: sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==}
peerDependencies:
'@uppy/core': ^2.1.1
'@uppy/xhr-upload': ^2.0.3
dom7: ^3.0.0
is-hotkey: ^0.2.0
lodash.camelcase: ^4.3.0
lodash.clonedeep: ^4.5.0
lodash.debounce: ^4.0.8
lodash.foreach: ^4.5.0
lodash.isequal: ^4.5.0
lodash.throttle: ^4.1.1
lodash.toarray: ^4.4.0
nanoid: ^3.2.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/editor-for-vue@5.1.12':
resolution: {integrity: sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==}
peerDependencies:
'@wangeditor/editor': '>=5.1.0'
vue: ^3.0.5
'@wangeditor/editor@5.1.23':
resolution: {integrity: sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==}
'@wangeditor/list-module@1.0.5':
resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
peerDependencies:
'@wangeditor/core': 1.x
dom7: ^3.0.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/table-module@1.1.4':
resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
peerDependencies:
'@wangeditor/core': 1.x
dom7: ^3.0.0
lodash.isequal: ^4.5.0
lodash.throttle: ^4.1.1
nanoid: ^3.2.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/upload-image-module@1.0.2':
resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
peerDependencies:
'@uppy/core': ^2.0.3
'@uppy/xhr-upload': ^2.0.3
'@wangeditor/basic-modules': 1.x
'@wangeditor/core': 1.x
dom7: ^3.0.0
lodash.foreach: ^4.5.0
slate: ^0.72.0
snabbdom: ^3.1.0
'@wangeditor/video-module@1.1.4':
resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
peerDependencies:
'@uppy/core': ^2.1.4
'@uppy/xhr-upload': ^2.0.7
'@wangeditor/core': 1.x
dom7: ^3.0.0
nanoid: ^3.2.0
slate: ^0.72.0
snabbdom: ^3.1.0
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -1000,6 +1120,9 @@ packages:
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
engines: {node: '>= 12.0.0'}
compute-scroll-into-view@1.0.20:
resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -1028,6 +1151,10 @@ packages:
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
d@1.0.2:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'}
dayjs@1.11.19:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
@@ -1069,6 +1196,9 @@ packages:
resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dom7@3.0.0:
resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -1109,6 +1239,17 @@ packages:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
es5-ext@0.10.64:
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
engines: {node: '>=0.10'}
es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
es6-symbol@3.1.4:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'}
esbuild@0.25.12:
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'}
@@ -1313,6 +1454,10 @@ packages:
jiti:
optional: true
esniff@2.0.1:
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
engines: {node: '>=0.10'}
espree@10.4.0:
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1340,9 +1485,15 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1480,6 +1631,12 @@ packages:
html-entities@2.6.0:
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
html-void-elements@2.0.1:
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
i18next@20.6.1:
resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1488,6 +1645,9 @@ packages:
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
engines: {node: '>= 4'}
immer@9.0.21:
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
immutable@5.1.4:
resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==}
@@ -1515,10 +1675,20 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-hotkey@0.2.0:
resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
is-url@1.2.4:
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
is-what@5.5.0:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'}
@@ -1585,9 +1755,31 @@ packages:
lodash: '*'
lodash-es: '*'
lodash.camelcase@4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
lodash.foreach@4.5.0:
resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==}
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
lodash.toarray@4.4.0:
resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -1738,6 +1930,9 @@ packages:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-match@1.0.2:
resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
@@ -1761,6 +1956,9 @@ packages:
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
namespace-emitter@2.0.1:
resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -1773,6 +1971,9 @@ packages:
resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==}
engines: {node: '>=18'}
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@@ -1889,6 +2090,9 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
preact@10.28.0:
resolution: {integrity: sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -1902,6 +2106,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
prismjs@1.30.0:
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
engines: {node: '>=6'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@@ -1956,6 +2164,9 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
scroll-into-view-if-needed@2.2.31:
resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
scslre@0.3.0:
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
engines: {node: ^14.0.0 || >=16.0.0}
@@ -1976,6 +2187,18 @@ packages:
sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
slate-history@0.66.0:
resolution: {integrity: sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==}
peerDependencies:
slate: '>=0.65.3'
slate@0.72.8:
resolution: {integrity: sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==}
snabbdom@3.6.3:
resolution: {integrity: sha512-W2lHLLw2qR2Vv0DcMmcxXqcfdBaIcoN+y/86SmHv8fn4DazEQSH6KN3TjZcWvwujW56OHiiirsbHWZb4vx/0fg==}
engines: {node: '>=12.17.0'}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -1993,6 +2216,9 @@ packages:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'}
ssr-window@3.0.0:
resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
strip-indent@4.1.1:
resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==}
engines: {node: '>=12'}
@@ -2017,6 +2243,9 @@ packages:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'}
tiny-warning@1.0.3:
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
tinyexec@1.0.2:
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
engines: {node: '>=18'}
@@ -2052,6 +2281,9 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
type@2.7.3:
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@@ -2218,6 +2450,9 @@ packages:
engines: {node: '>= 8'}
hasBin: true
wildcard@1.1.2:
resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
@@ -2305,6 +2540,8 @@ snapshots:
dependencies:
'@babel/types': 7.28.5
'@babel/runtime@7.28.4': {}
'@babel/types@7.28.5':
dependencies:
'@babel/helper-string-parser': 7.27.1
@@ -2705,12 +2942,16 @@ snapshots:
'@sxzz/popperjs-es@2.11.7': {}
'@transloadit/prettier-bytes@0.0.7': {}
'@types/debug@4.1.12':
dependencies:
'@types/ms': 2.1.0
'@types/estree@1.0.8': {}
'@types/event-emitter@0.3.5': {}
'@types/json-schema@7.0.15': {}
'@types/lodash-es@4.17.12':
@@ -2824,6 +3065,35 @@ snapshots:
'@typescript-eslint/types': 8.49.0
eslint-visitor-keys: 4.2.1
'@uppy/companion-client@2.2.2':
dependencies:
'@uppy/utils': 4.1.3
namespace-emitter: 2.0.1
'@uppy/core@2.3.4':
dependencies:
'@transloadit/prettier-bytes': 0.0.7
'@uppy/store-default': 2.1.1
'@uppy/utils': 4.1.3
lodash.throttle: 4.1.1
mime-match: 1.0.2
namespace-emitter: 2.0.1
nanoid: 3.3.11
preact: 10.28.0
'@uppy/store-default@2.1.1': {}
'@uppy/utils@4.1.3':
dependencies:
lodash.throttle: 4.1.1
'@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4)':
dependencies:
'@uppy/companion-client': 2.2.2
'@uppy/core': 2.3.4
'@uppy/utils': 4.1.3
nanoid: 3.3.11
'@vitejs/plugin-vue@6.0.2(vite@7.2.7(@types/node@24.10.3)(sass@1.96.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50
@@ -2962,6 +3232,114 @@ snapshots:
- '@vue/composition-api'
- vue
'@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
is-url: 1.2.4
lodash.throttle: 4.1.1
nanoid: 3.3.11
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/code-highlight@1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
prismjs: 1.30.0
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@types/event-emitter': 0.3.5
'@uppy/core': 2.3.4
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
dom7: 3.0.0
event-emitter: 0.3.5
html-void-elements: 2.0.1
i18next: 20.6.1
is-hotkey: 0.2.0
lodash.camelcase: 4.3.0
lodash.clonedeep: 4.5.0
lodash.debounce: 4.0.8
lodash.foreach: 4.5.0
lodash.isequal: 4.5.0
lodash.throttle: 4.1.1
lodash.toarray: 4.4.0
nanoid: 3.3.11
scroll-into-view-if-needed: 2.2.31
slate: 0.72.8
slate-history: 0.66.0(slate@0.72.8)
snabbdom: 3.6.3
'@wangeditor/editor-for-vue@5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@wangeditor/editor': 5.1.23
vue: 3.5.25(typescript@5.9.3)
'@wangeditor/editor@5.1.23':
dependencies:
'@uppy/core': 2.3.4
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/code-highlight': 1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/list-module': 1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/table-module': 1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/upload-image-module': 1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/video-module': 1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
is-hotkey: 0.2.0
lodash.camelcase: 4.3.0
lodash.clonedeep: 4.5.0
lodash.debounce: 4.0.8
lodash.foreach: 4.5.0
lodash.isequal: 4.5.0
lodash.throttle: 4.1.1
lodash.toarray: 4.4.0
nanoid: 3.3.11
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/list-module@1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/table-module@1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
lodash.isequal: 4.5.0
lodash.throttle: 4.1.1
nanoid: 3.3.11
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/upload-image-module@1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@uppy/core': 2.3.4
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
lodash.foreach: 4.5.0
slate: 0.72.8
snabbdom: 3.6.3
'@wangeditor/video-module@1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
dependencies:
'@uppy/core': 2.3.4
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
dom7: 3.0.0
nanoid: 3.3.11
slate: 0.72.8
snabbdom: 3.6.3
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
acorn: 8.15.0
@@ -3075,6 +3453,8 @@ snapshots:
comment-parser@1.4.1: {}
compute-scroll-into-view@1.0.20: {}
concat-map@0.0.1: {}
confbox@0.1.8: {}
@@ -3099,6 +3479,11 @@ snapshots:
csstype@3.2.3: {}
d@1.0.2:
dependencies:
es5-ext: 0.10.64
type: 2.7.3
dayjs@1.11.19: {}
debug@4.4.3:
@@ -3126,6 +3511,10 @@ snapshots:
diff-sequences@27.5.1: {}
dom7@3.0.0:
dependencies:
ssr-window: 3.0.0
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -3178,6 +3567,24 @@ snapshots:
has-tostringtag: 1.0.2
hasown: 2.0.2
es5-ext@0.10.64:
dependencies:
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esniff: 2.0.1
next-tick: 1.1.0
es6-iterator@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-symbol: 3.1.4
es6-symbol@3.1.4:
dependencies:
d: 1.0.2
ext: 1.7.0
esbuild@0.25.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.12
@@ -3487,6 +3894,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
esniff@2.0.1:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
event-emitter: 0.3.5
type: 2.7.3
espree@10.4.0:
dependencies:
acorn: 8.15.0
@@ -3513,8 +3927,17 @@ snapshots:
esutils@2.0.3: {}
event-emitter@0.3.5:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
exsolve@1.0.8: {}
ext@1.7.0:
dependencies:
type: 2.7.3
fast-deep-equal@3.1.3: {}
fast-diff@1.3.0: {}
@@ -3629,10 +4052,18 @@ snapshots:
html-entities@2.6.0: {}
html-void-elements@2.0.1: {}
i18next@20.6.1:
dependencies:
'@babel/runtime': 7.28.4
ignore@5.3.2: {}
ignore@7.0.5: {}
immer@9.0.21: {}
immutable@5.1.4: {}
import-fresh@3.3.1:
@@ -3654,9 +4085,15 @@ snapshots:
dependencies:
is-extglob: 2.1.1
is-hotkey@0.2.0: {}
is-number@7.0.0:
optional: true
is-plain-object@5.0.0: {}
is-url@1.2.4: {}
is-what@5.5.0: {}
isexe@2.0.0: {}
@@ -3713,8 +4150,22 @@ snapshots:
lodash: 4.17.21
lodash-es: 4.17.21
lodash.camelcase@4.3.0: {}
lodash.clonedeep@4.5.0: {}
lodash.debounce@4.0.8: {}
lodash.foreach@4.5.0: {}
lodash.isequal@4.5.0: {}
lodash.merge@4.6.2: {}
lodash.throttle@4.1.1: {}
lodash.toarray@4.4.0: {}
lodash@4.17.21: {}
longest-streak@3.1.0: {}
@@ -4048,6 +4499,10 @@ snapshots:
mime-db@1.52.0: {}
mime-match@1.0.2:
dependencies:
wildcard: 1.1.2
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
@@ -4073,12 +4528,16 @@ snapshots:
muggle-string@0.4.1: {}
namespace-emitter@2.0.1: {}
nanoid@3.3.11: {}
natural-compare@1.4.0: {}
natural-orderby@5.0.0: {}
next-tick@1.1.0: {}
node-addon-api@7.1.1:
optional: true
@@ -4182,6 +4641,8 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
preact@10.28.0: {}
prelude-ls@1.2.1: {}
prettier-linter-helpers@1.0.0:
@@ -4190,6 +4651,8 @@ snapshots:
prettier@3.7.4: {}
prismjs@1.30.0: {}
proxy-from-env@1.1.0: {}
punycode@2.3.1: {}
@@ -4257,6 +4720,10 @@ snapshots:
optionalDependencies:
'@parcel/watcher': 2.5.1
scroll-into-view-if-needed@2.2.31:
dependencies:
compute-scroll-into-view: 1.0.20
scslre@0.3.0:
dependencies:
'@eslint-community/regexpp': 4.12.2
@@ -4273,6 +4740,19 @@ snapshots:
sisteransi@1.0.5: {}
slate-history@0.66.0(slate@0.72.8):
dependencies:
is-plain-object: 5.0.0
slate: 0.72.8
slate@0.72.8:
dependencies:
immer: 9.0.21
is-plain-object: 5.0.0
tiny-warning: 1.0.3
snabbdom@3.6.3: {}
source-map-js@1.2.1: {}
spdx-exceptions@2.5.0: {}
@@ -4286,6 +4766,8 @@ snapshots:
speakingurl@14.0.1: {}
ssr-window@3.0.0: {}
strip-indent@4.1.1: {}
strip-json-comments@3.1.1: {}
@@ -4304,6 +4786,8 @@ snapshots:
tapable@2.3.0: {}
tiny-warning@1.0.3: {}
tinyexec@1.0.2: {}
tinyglobby@0.2.15:
@@ -4338,6 +4822,8 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
type@2.7.3: {}
typescript@5.9.3: {}
ufo@1.6.1: {}
@@ -4474,6 +4960,8 @@ snapshots:
dependencies:
isexe: 2.0.0
wildcard@1.1.2: {}
word-wrap@1.2.5: {}
xml-name-validator@4.0.0: {}
@@ -3,7 +3,15 @@ import { useCommonStore } from '@/store/common'
import AreaSelect from './AreaSelect.vue'
import IndustrySelect from './IndustrySelect.vue'
const emit = defineEmits<{
(e: 'search'): void
}>()
const commonStore = useCommonStore()
function onSearch() {
emit('search')
}
</script>
<template>
@@ -28,7 +36,7 @@ const commonStore = useCommonStore()
/>
</div>
<div class="search">
<div class="search" @click="onSearch">
<i-tdesign:search />
</div>
</div>
@@ -44,7 +52,7 @@ const commonStore = useCommonStore()
border: 0;
color: #000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
background-color: #f4f4f4;
.query-item {
flex: 1;
@@ -0,0 +1,38 @@
import { createApp } from 'vue'
import UploadProgress from './index.vue'
let app: ReturnType<typeof createApp> | null = null
let instance: any = null
export function showUploadProgress(status: ProgressStatus = 'uploading') {
if (!app) {
const container = document.createElement('div')
document.body.appendChild(container)
app = createApp(UploadProgress)
instance = app.mount(container)
}
instance.open()
instance.setStatus(status) // 外部传入状态
}
export function updateUploadProgress(percent: number, status: ProgressStatus = 'uploading') {
if (instance) {
instance.setPercent(percent)
instance.setStatus(status) // 外部传入状态
if (percent >= 100) {
setTimeout(() => {
closeUploadProgress()
}, 800) // 100%后等一下再关闭,显得自然
}
}
}
export function closeUploadProgress() {
if (instance) {
instance.close()
}
}
export type ProgressStatus = 'uploading' | 'completed' | 'failed'
@@ -0,0 +1,128 @@
<script setup lang="ts">
import type { ProgressStatus } from '.'
import { computed, ref, watch } from 'vue'
// 状态变量
const visible = ref(false)
const percent = ref(0)
const statusText = ref('正在上传,请稍候')
const status = ref<ProgressStatus>('uploading')
// 监听 percent 变化,更新状态文本
watch(percent, (newPercent) => {
const clampedPercent = Math.min(newPercent, 1)
percent.value = clampedPercent
if (clampedPercent === 1) {
status.value = 'completed'
}
else if (clampedPercent < 1 && status.value !== 'failed') {
status.value = 'uploading'
}
})
// 监听上传状态变化,更新状态文本
watch(status, (newStatus) => {
if (newStatus === 'completed') {
statusText.value = '上传完毕'
}
else if (newStatus === 'uploading') {
statusText.value = '正在上传,请稍候 . . .'
}
else if (newStatus === 'failed') {
statusText.value = '上传失败,请稍后再试 . . .'
}
})
// 获取进度条状态,上传失败时显示为 "exception"
const getProgressStatus = computed(() => {
if (status.value === 'failed') {
return 'exception'
}
return percent.value < 1 ? '' : 'success'
})
// 控制上传进度的函数
function open() {
percent.value = 0
visible.value = true
status.value = 'uploading' // 开始上传时重置状态
statusText.value = '正在上传,请稍候 . . .'
}
function close() {
visible.value = false
}
function setPercent(p: number) {
percent.value = Number.parseFloat((p / 100).toFixed(2)) // 保留两位小数
}
defineExpose({
open,
close,
setPercent,
setStatus: (newStatus: ProgressStatus) => {
status.value = newStatus // 使用 ProgressStatus 类型
},
})
</script>
<template>
<Teleport to="body">
<transition name="fade">
<div v-if="visible" class="upload-progress-mask">
<div class="upload-progress-card">
<div class="upload-progress-title" :class="[status === 'failed' ? 'error' : '']">
{{ statusText }}
</div>
<el-progress :percentage="percent" :stroke-width="10" :status="getProgressStatus" />
</div>
</div>
</transition>
</Teleport>
</template>
<style scoped>
.upload-progress-mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 3000;
display: flex;
justify-content: center;
align-items: center;
}
.upload-progress-card {
background: #ffffff;
padding: 40px 50px;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
text-align: center;
min-width: 320px;
}
.upload-progress-title {
font-size: 22px;
font-weight: bold;
margin-bottom: 30px;
color: #333;
}
.upload-progress-title.error {
color: red; /* 上传失败时,字体颜色变为红色 */
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
@@ -0,0 +1,67 @@
import type { IButtonMenu, IDomEditor } from '@wangeditor/editor'
import { Boot } from '@wangeditor/editor'
// 当前的点击处理器,始终指向最新传入的函数
let currentClickHandler: (() => void) | null = null
// 是否已经注册过菜单
let hasRegistered = false
class PreviewButtonMenu implements IButtonMenu {
title = '预览'
iconSvg = `
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 16 16">
<path fill="currentColor" fill-rule="evenodd" d="M12 4.57a.5.5 0 0 0-.024-.235l-.013-.063a1.5 1.5 0 0 0-.18-.434c-.092-.15-.222-.28-.482-.54L8.711.707c-.259-.26-.389-.39-.54-.483a1.5 1.5 0 0 0-.496-.193a.5.5 0 0 0-.235-.024C7.329.004 7.194.004 7.015.004h-2.21c-1.68 0-2.52 0-3.16.327a3.02 3.02 0 0 0-1.31 1.31C.008 2.283.008 3.12.008 4.8v6.4c0 1.68 0 2.52.327 3.16a3.02 3.02 0 0 0 1.31 1.31c.642.327 1.48.327 3.16.327h2.423c.401 0 .602-.523.347-.832a.45.45 0 0 0-.345-.168H4.8c-.857 0-1.44-.001-1.89-.038c-.438-.036-.663-.1-.819-.18a2 2 0 0 1-.874-.874c-.08-.156-.145-.38-.18-.819c-.036-.45-.037-1.03-.037-1.89v-6.4c0-.857 0-1.44.037-1.89c.036-.438.101-.663.18-.819c.192-.376.498-.682.874-.874c.156-.08.381-.145.82-.18C3.36.997 3.94.997 4.8.997H7v3.5a.5.5 0 0 0 .5.5H11v.547c0 .25.207.45.456.473c.285.025.543-.188.543-.474V4.99c0-.178 0-.313-.005-.425zM8 1.41L10.59 4H8z" clip-rule="evenodd"/>
<path fill="currentColor" fill-rule="evenodd" d="M11 15c.834 0 1.61-.255 2.25-.691l1.47 1.47a.749.749 0 1 0 1.06-1.06l-1.47-1.47c.436-.641.691-1.41.691-2.25c0-2.21-1.79-4-4-4s-4 1.79-4 4s1.79 4 4 4zm0-1c1.66 0 3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3s1.34 3 3 3" clip-rule="evenodd"/>
</svg>
`
tag = 'button'
getValue(): string | boolean {
return ''
}
isActive(): boolean {
return false
}
isDisabled(): boolean {
return false
}
exec(editor: IDomEditor): void {
if (this.isDisabled())
return
currentClickHandler?.() // 始终执行最新的回调
}
}
// 提供注册函数,允许多次调用,但只注册一次菜单
export function registerPreviewMenu(handleClick: () => void) {
currentClickHandler = handleClick
if (hasRegistered)
return
try {
Boot.registerMenu({
key: 'preview',
factory: () => new PreviewButtonMenu(),
})
hasRegistered = true
}
catch (e) {
if (!/duplicate/i.test(String(e))) {
console.warn('注册预览菜单失败:', e)
}
}
}
// 菜单插入配置
export const toolbarConfig = {
excludeKeys: ['codeBlock', 'fullScreen', 'code'],
insertKeys: {
index: 32,
keys: ['preview'],
},
}
@@ -0,0 +1,180 @@
<script setup lang="ts">
import type { PropType } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { ElMessage } from 'element-plus'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
import { uploadImage, uploadToAliyun, uploadVideo } from '@/utils/file'
import { registerPreviewMenu, toolbarConfig } from './config'
import Directory from './modules/directory.vue'
import '@wangeditor/editor/dist/css/style.css'
const props = defineProps({
mode: {
type: String as PropType<'edit' | 'view'>,
default: 'edit',
},
modelValue: {
type: String,
default: '',
},
showDirecotry: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['update:modelValue'])
// 内容 HTML
const valueHtml = ref('')
// 只读副本
const previewHtml = ref('')
const showPreview = ref(false)
watch(
() => props.modelValue,
(newVal) => {
valueHtml.value = newVal ?? ''
},
{ immediate: true },
)
onMounted(() => {
registerPreviewMenu(() => {
previewHtml.value = valueHtml.value
showPreview.value = true
})
})
const toolbarClass = computed(() => {
return props.mode === 'view' ? 'toolbar-view' : 'toolbar-edit'
})
const editorClass = computed(() => {
return props.mode === 'view' ? 'editor-view' : 'editor-edit'
})
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
defineExpose({
getText: () => {
if (editorRef.value) {
return editorRef.value.getText()
}
else {
console.error('Editor not initialized')
return ''
}
},
})
function handleChange() {
emit('update:modelValue', valueHtml.value)
}
const editorConfig: any = {
placeholder: props.mode === 'edit' ? '请输入内容...' : '',
readOnly: props.mode === 'view',
MENU_CONF: {}, // ✅ 这一步不能漏!
}
editorConfig.MENU_CONF.uploadImage = {
// 自定义选择图片
customBrowseAndUpload(insertFn: any) {
uploadImage().then((data) => {
if (data) {
uploadToAliyun(data.blob, data.name, data.size).then((res) => {
insertFn(res.url, res.fileName, '')
})
}
})
},
}
editorConfig.MENU_CONF.uploadVideo = {
customBrowseAndUpload(insertFn: any) {
uploadVideo().then((data) => {
if (data) {
uploadToAliyun(data.blob, data.name, data.size).then((res) => {
insertFn(res.url, res.fileName, '')
})
}
else {
ElMessage.error('上传失败,请稍后再试!')
}
})
},
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null)
return
editor.destroy()
})
function handleCreated(editor: any) {
editorRef.value = editor
nextTick(() => {})
}
</script>
<template>
<div class="editor-container">
<div class="main">
<Toolbar v-if="props.mode === 'edit'" :class="toolbarClass" class="toolbar" :editor="editorRef" :default-config="toolbarConfig" />
<Editor key="main" v-model="valueHtml" :class="editorClass" class="editor" :default-config="editorConfig" @on-change="handleChange" @on-created="handleCreated" />
</div>
<Directory v-if="showDirecotry" v-model:content="valueHtml" class="directory" />
</div>
<!-- <Preview v-model:visible="showPreview" :content="previewHtml" /> -->
</template>
<style lang="scss" scoped>
.toolbar {
}
.toolbar-view {
}
.toolbar-edit {
border: 1px solid #ccc;
}
.editor {
overflow-y: hidden;
:deep(.w-e-text-container video) {
width: 100% !important;
}
}
.editor-view {
height: auto;
:deep(.w-e-text-container) {
background-color: transparent;
}
:deep(.w-e-text-container .w-e-scroll [data-slate-editor]) {
overflow-y: auto;
padding: 0 0px !important;
}
}
.editor-edit {
height: 500px !important;
border: 1px solid #ccc;
border-top: transparent;
}
.editor-container {
display: flex;
width: 100%;
height: 100%;
.directory {
width: 200px;
height: 450px;
}
.main {
min-width: 0;
flex: 1;
}
}
</style>
@@ -0,0 +1,176 @@
<script setup lang="ts">
import { nextTick, ref, watch } from 'vue'
defineOptions({
name: 'WangEditorDirecotry',
})
const props = defineProps({
content: {
type: String,
},
top: {
type: Number,
},
})
const directory = ref<any[]>([])
const collapsed = ref(false)
function toggleCollapse() {
collapsed.value = !collapsed.value
}
function scrollTo(id: any) {
const el = document.getElementById(id)
if (el) {
if (props.top) {
const rect = el.getBoundingClientRect()
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
const top = rect.top + scrollTop - props.top
window.scrollTo({
top,
behavior: 'smooth',
})
}
else {
el.scrollIntoView({
behavior: 'smooth', // 平滑滚动
block: 'start', // 元素滚动到视口顶部
inline: 'nearest', // 元素在水平方向上的滚动对齐方式
})
}
}
}
function throttle(fn: any) {
let isRunning = false
return function (...args: any) {
if (!isRunning) {
isRunning = true
requestAnimationFrame(() => {
fn(...args)
isRunning = false
})
}
}
}
function doGenerateDirectory() {
const root = document.querySelector('.editor')
if (!root)
return
const headings = Array.from(root.querySelectorAll('h1, h2, h3'))
const toc = headings.map((heading, idx) => {
if (!heading.id)
heading.id = `section-${idx + 1}`
return {
id: heading.id,
text: heading.textContent || '',
level: +heading.tagName[1], // 1 => h1, 2 => h2, 3 => h3
index: idx,
}
})
directory.value = toc
}
const updateDirectory = throttle(doGenerateDirectory)
watch(
() => props.content,
(newContent) => {
if (newContent) {
nextTick(() => {
updateDirectory()
})
}
},
{ immediate: true },
)
</script>
<template>
<div class="directory-card" :class="{ collapsed }">
<div class="directory-header" @click="toggleCollapse">
<div class="directory-header-left">
<i-material-symbols:folder-copy-outline />
<span>目录</span>
</div>
</div>
<div v-show="!collapsed" class="directory-content">
<div v-for="item in directory" :key="item.id" class="directory-item" :class="`level-${item.level}`" @click="scrollTo(item.id)">
{{ item.text }}
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.directory-card {
display: flex;
flex-direction: column;
background-color: #fff;
overflow: hidden;
&.collapsed {
height: 44px !important;
box-shadow: none;
}
}
.directory-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1rem;
height: 44px;
font-size: 16px;
font-weight: bold;
border-bottom: 1px solid #e0e0e0;
cursor: pointer;
transition: background-color 0.2s ease;
.directory-header-left {
display: flex;
gap: 8px;
align-items: center;
font-size: 14px;
color: #333;
}
}
.directory-content {
flex: 1;
padding: 1rem;
overflow-y: auto;
word-break: break-all;
.directory-item {
padding: 8px 12px;
cursor: pointer;
font-size: 14px;
color: #333;
&.level-1 {
font-weight: 600;
padding-left: 0;
font-size: 16px;
}
&.level-2 {
padding-left: 20px;
font-size: 14px;
}
&.level-3 {
padding-left: 40px;
font-size: 12px;
}
&:hover {
color: #007aff;
}
}
}
</style>
@@ -0,0 +1,125 @@
<script setup lang="ts">
import { Editor } from '@wangeditor/editor-for-vue'
import { ref, shallowRef, watch } from 'vue'
import '@wangeditor/editor/dist/css/style.css'
// Props 定义
const props = withDefaults(
defineProps<{
content?: string
visible?: boolean
}>(),
{
content: '',
visible: false,
},
)
const emit = defineEmits(['update:visible'])
// 编辑器配置
const editorConfig = {
placeholder: '暂无内容',
readOnly: true,
MENU_CONF: {},
}
const fullscreen = ref(false)
const localVisible = ref(props.visible)
const editorRef = shallowRef()
// 同步 props.visible 到 localVisible
watch(
() => props.visible,
(val) => {
localVisible.value = val
},
{ immediate: true },
)
watch(
() => props.content,
(val) => {
if (editorRef.value) {
editorRef.value.setHtml(val)
}
},
{ immediate: true },
)
// 编辑器创建回调
function handleCreated(editor: any) {
editorRef.value = editor
}
// 更新 visible 的统一方法
function handleVisibleChange(val: boolean) {
localVisible.value = val
emit('update:visible', val)
}
// 关闭操作
function closeModal() {
fullscreen.value = false
emit('update:visible', false)
handleVisibleChange(false)
}
</script>
<template>
<a-modal v-bind="$attrs" :visible="localVisible" :footer="false" :closable="false" :fullscreen="fullscreen" :width="1100" modal-class="custom-modal" @update:visible="handleVisibleChange">
<template #title>
<div class="header">
<div />
<div class="title">
预览
</div>
<div class="actions">
<div class="action" @click="fullscreen = !fullscreen">
<i-material-symbols:fullscreen-exit v-if="fullscreen" />
<i-material-symbols:fullscreen v-else />
</div>
<div class="action" @click="closeModal">
<i i-material-symbols:close-rounded />
</div>
</div>
</div>
</template>
<div :class="fullscreen ? '' : 'editor'">
<Editor key="preview" class="editorView" :default-config="editorConfig" @on-created="handleCreated" />
</div>
</a-modal>
</template>
<style lang="scss" scoped>
.header {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.title {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.actions {
display: flex;
gap: 16px;
font-size: 18px;
.action {
cursor: pointer;
}
}
.editor {
max-height: 500px;
}
.editor-view {
overflow-y: hidden;
height: auto;
:deep(.w-e-text-container .w-e-scroll [data-slate-editor]) {
padding: 0 0px !important;
}
}
</style>
@@ -1,4 +1,8 @@
<script lang="ts" setup>
import {
CircleClose,
User,
} from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
import { useUserStore } from '@/store/user'
@@ -20,8 +24,6 @@ function navigateTo(path: string) {
function exitLogin() {
userStore.clearUserInfo()
navigateTo('/auth/login')
}
function isActive(path: string) {
@@ -68,8 +70,10 @@ function isActive(path: string) {
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item @click="exitLogin()">
<el-dropdown-item :icon="User" @click="navigateTo('/settings')">
个人中心
</el-dropdown-item>
<el-dropdown-item :icon="CircleClose" @click="exitLogin()">
退出登录
</el-dropdown-item>
</el-dropdown-menu>
@@ -1,6 +1,5 @@
<script lang="ts" setup>
import Header from './components/header.vue'
</script>
<template>
@@ -9,26 +8,25 @@ import Header from './components/header.vue'
<div class="content">
<RouterView />
</div>
<footer class="footer">
<!-- <footer class="footer">
footer
</footer>
</footer> -->
</div>
</template>
<style lang="scss" scoped>
.app {
position: relative;
background-color: #eff2f6;
}
.content {
padding-top: 60px;
height: 1800px;
}
.footer {
margin-top: 32px;
height: 100px;
background-color: #ccc;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
@@ -1,6 +1,14 @@
import type { InitBaseDataResult } from '@/types/base'
import { httpGet } from '@/request/utils'
import type { AddFileParams, GetAliyunKeyResult, InitBaseDataResult } from '@/types/base'
import { httpGet, httpPostJson } from '@/request/utils'
export function initBaseApi() {
return httpGet<InitBaseDataResult>(`/base/init`)
}
export function getAliyunKeyApi() {
return httpGet<GetAliyunKeyResult>(`/base/file/getAliyunKey`)
}
export function addFileApi(params: AddFileParams) {
return httpPostJson<void>(`/base/file/add`, params)
}
@@ -1,5 +1,5 @@
import type { RecommendCompany, RecommendHotCompany } from '@/types/company'
import { httpGet } from '@/request/utils'
import type { CompanyDetail, CompanyListItem, QueryCompanyParams, RecommendCompany, RecommendHotCompany } from '@/types/company'
import { httpGet, httpPostJson } from '@/request/utils'
export function getRecommendCompanyApi() {
return httpGet<RecommendCompany[]>('/company/recommend')
@@ -8,3 +8,11 @@ export function getRecommendCompanyApi() {
export function getRecommendHotCompanyApi() {
return httpGet<RecommendHotCompany[]>('/company/recommend/hot')
}
export function queryCompanyApi(params: QueryCompanyParams) {
return httpPostJson<BasePageResult<CompanyListItem>>('/company/query', params)
}
export function getCompanyDetailApi(id: number) {
return httpGet<CompanyDetail>(`/company/detail/${id}`)
}
@@ -1,9 +1,9 @@
import type { App } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/layout/index.vue'
const router = createRouter({
history: createWebHashHistory(),
history: createWebHistory(),
strict: true,
routes: [
{
@@ -18,6 +18,10 @@ const router = createRouter({
path: '/company',
component: () => import('@/views/company/index.vue'),
},
{
path: '/company/detail',
component: () => import('@/views/company/detail/index.vue'),
},
],
},
{
@@ -14,63 +14,10 @@ export const useCommonStore = defineStore(
name: '',
})
/**
* 根据 Area id 获取完整路径,例如 "天津市/滨海新区/塘沽"
*/
function getAreaFullPathById(id: string): string {
// 递归查找节点
function findNode(id: string, nodes: Area[]): Area | null {
for (const node of nodes) {
if (node.id === id)
return node
if (node.children && node.children.length) {
const found = findNode(id, node.children)
if (found)
return found
}
}
return null
}
const node = findNode(id, areaOptions)
if (!node)
return ''
// 构建完整路径
const names: string[] = []
let current: Area | undefined | null = node
while (current) {
names.unshift(current.name)
current = current.fatherId ? findNode(current.fatherId, areaOptions) || undefined : undefined
}
return names.join(',')
}
function getAreaIdByFullPath(fullPath: string): string | null {
const names = fullPath.split(',').map(s => s.trim())
if (!names.length)
return null
let currentNodes = areaOptions
let foundNode: Area | null = null
for (const name of names) {
foundNode = currentNodes.find(n => n.name === name) || null
if (!foundNode)
return null
currentNodes = foundNode.children || []
}
return foundNode?.id || null
}
return {
areaOptions,
industryOptions,
companyQuery,
getAreaFullPathById,
getAreaIdByFullPath,
}
},
)
@@ -1,3 +1,7 @@
html, body {
background-color: #f7f7f7;
}
body::-webkit-scrollbar {
display: none;
}
@@ -12,25 +12,45 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AreaSelect: typeof import('./../components/AreaSelect.vue')['default']
Directory: typeof import('./../components/wang-editor/modules/directory.vue')['default']
HelloWorld: typeof import('./../components/HelloWorld.vue')['default']
ICarbonAccessibility: typeof import('~icons/carbon/accessibility')['default']
'IFa7Solid:userShield': typeof import('~icons/fa7-solid/user-shield')['default']
'IIc:twotoneHeadphones': typeof import('~icons/ic/twotone-headphones')['default']
'IIconoir:infoCircleSolid': typeof import('~icons/iconoir/info-circle-solid')['default']
'IMaterialSymbols:call': typeof import('~icons/material-symbols/call')['default']
'IMaterialSymbols:chatBubbleOutline': typeof import('~icons/material-symbols/chat-bubble-outline')['default']
'IMaterialSymbols:folderCopyOutline': typeof import('~icons/material-symbols/folder-copy-outline')['default']
'IMaterialSymbols:fullscreen': typeof import('~icons/material-symbols/fullscreen')['default']
'IMaterialSymbols:fullscreenExit': typeof import('~icons/material-symbols/fullscreen-exit')['default']
'IMaterialSymbols:locationOn': typeof import('~icons/material-symbols/location-on')['default']
'IMaterialSymbols:locationOnOutlineRounded': typeof import('~icons/material-symbols/location-on-outline-rounded')['default']
'IMaterialSymbols:lockOpenRightSharp': typeof import('~icons/material-symbols/lock-open-right-sharp')['default']
'IMaterialSymbols:mail': typeof import('~icons/material-symbols/mail')['default']
IMdiAccountBox: typeof import('~icons/mdi/account-box')['default']
'IMingcute:chat1Fill': typeof import('~icons/mingcute/chat1-fill')['default']
'IMingcute:eye2Line': typeof import('~icons/mingcute/eye2-line')['default']
Industry: typeof import('../components/IndustrySelect.vue')['default']
IndustrySelect: typeof import('./../components/IndustrySelect.vue')['default']
'INrk:show': typeof import('~icons/nrk/show')['default']
'IRi:buildingFill': typeof import('~icons/ri/building-fill')['default']
'IRi:buildingLine': typeof import('~icons/ri/building-line')['default']
'IRi:information2Line': typeof import('~icons/ri/information2-line')['default']
'IRi:informationFill': typeof import('~icons/ri/information-fill')['default']
'IRi:message3Fill': typeof import('~icons/ri/message3-fill')['default']
'ISolar:chatRoundBold': typeof import('~icons/solar/chat-round-bold')['default']
'ISolar:chatRoundCallBroken': typeof import('~icons/solar/chat-round-call-broken')['default']
'ISolar:eyeBroken': typeof import('~icons/solar/eye-broken')['default']
'ISolar:eyeClosedBroken': typeof import('~icons/solar/eye-closed-broken')['default']
'IStreamlineUltimate:informationCircleBold': typeof import('~icons/streamline-ultimate/information-circle-bold')['default']
'ITdesign:notification': typeof import('~icons/tdesign/notification')['default']
'ITdesign:search': typeof import('~icons/tdesign/search')['default']
Preview: typeof import('./../components/wang-editor/modules/preview.vue')['default']
QueryCompany: typeof import('./../components/QueryCompany.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SafeImage: typeof import('./../components/SafeImage.vue')['default']
UploadProgress: typeof import('./../components/upload-progress/index.vue')['default']
WangEditor: typeof import('./../components/wang-editor/index.vue')['default']
}
}
@@ -19,6 +19,22 @@ export interface InitBaseDataResult {
export interface CompanyQuery {
industries: string[]
areas: string[]
areas: string[][]
name: string
}
export interface GetAliyunKeyResult {
accessid: string
policy: string
signature: string
dir: string
host: string
expire: string
callback: string
}
export interface AddFileParams {
fileName: string
fileSize: string
fileMapName: string
}
@@ -12,3 +12,44 @@ export interface RecommendHotCompany {
id: number
name: string
}
export interface QueryCompanyParams {
currentPage: number
pageSize: number
areas: string[]
industries: string[]
name: string
}
export interface CompanyListItem {
id: number
name: string
areas: string[]
industries: string[]
logo: string
profile: string
phone: string
email: string
}
export interface CompanyDetail {
id: number
name: string
areas: string[]
industries: string[]
logo: string
profile: string
phone: string
email: string
description: string
users: {
id: number
companyId: number
phone: string
email: string
role: number
position: string
name: string
}[]
}
+11
View File
@@ -7,4 +7,15 @@ declare global {
message: string
data: T
}
interface BasePageResult<T> {
total: number
records: T[]
}
interface Pagination {
total: number
current: number
pageSize: number
}
}
@@ -0,0 +1,243 @@
import { ElMessage } from 'element-plus'
import { closeUploadProgress, showUploadProgress, updateUploadProgress } from '@/components/upload-progress/index'
import { addFileApi, getAliyunKeyApi } from '@/request/api/base'
export interface UploadImageResponse {
name: string
size: string
url: string
blob: Blob
}
export function uploadImage(options: {
quality?: number
mimeType?: string
} = {}): Promise<UploadImageResponse> {
const { quality = 0.8, mimeType = 'image/webp' } = options
return new Promise((resolve, reject) => {
if (typeof document === 'undefined') {
reject(new Error('Require browser environment'))
return
}
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.style.display = 'none'
const processImage = (file: File): Promise<UploadImageResponse> => {
return new Promise((resolve, reject) => {
const img = new Image()
const objectURL = URL.createObjectURL(file)
img.onload = () => {
try {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (!ctx)
throw new Error('Canvas init failed')
canvas.width = img.width
canvas.height = img.height
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
URL.revokeObjectURL(objectURL)
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error('Compression failed'))
return
}
resolve({ name: file.name, size: blob.size.toString(), url: URL.createObjectURL(blob), blob })
},
mimeType,
quality,
)
}
catch (error) {
reject(error)
}
}
img.onerror = () => {
URL.revokeObjectURL(objectURL)
reject(new Error('Image load failed'))
}
img.src = objectURL
})
}
input.onchange = async (event) => {
const file = (event.target as HTMLInputElement).files?.[0]
if (!file) {
reject(new Error('No file selected'))
return
}
try {
if (!file.type.startsWith('image/')) {
throw new Error('Invalid image file')
}
const result = await processImage(file)
resolve(result)
}
catch (error) {
reject(error)
}
finally {
document.body.removeChild(input)
}
}
document.body.appendChild(input)
input.click()
})
}
export interface UploadVideoResponse {
name: string
size: string
url: string
blob: Blob
}
export function uploadVideo(): Promise<UploadVideoResponse> {
return new Promise((resolve, reject) => {
if (typeof document === 'undefined') {
reject(new Error('Require browser environment'))
return
}
const input = document.createElement('input')
input.type = 'file'
input.accept = 'video/*'
input.style.display = 'none'
input.onchange = (event) => {
const file = (event.target as HTMLInputElement).files?.[0]
if (!file) {
reject(new Error('No file selected'))
return
}
if (!file.type.startsWith('video/')) {
reject(new Error('Invalid video file'))
return
}
resolve({
name: file.name,
size: file.size.toString(),
url: URL.createObjectURL(file),
blob: file,
})
document.body.removeChild(input)
}
document.body.appendChild(input)
input.click()
})
}
export interface UploadToAliyunResponse {
url: string
fileName: string
fileSize: string
}
export function uploadToAliyun(blob: Blob, fileName: string, fileSize: string, onProgress?: (percent: number) => void): Promise<UploadToAliyunResponse> {
return new Promise((resolve, reject) => {
// 在开始上传时显示上传进度
showUploadProgress('uploading')
getAliyunKeyApi()
.then(async (res) => {
try {
const aliyunKey = res.data
const formData = new FormData()
const fileExt = fileName.includes('.') ? fileName.slice(fileName.lastIndexOf('.')) : ''
const uniqueName = `sl_${Date.now()}_${Math.random().toString(36).slice(2)}${fileExt}`
formData.append('key', `${aliyunKey.dir}${uniqueName}`)
formData.append('OSSAccessKeyId', aliyunKey.accessid)
formData.append('policy', aliyunKey.policy)
formData.append('Signature', aliyunKey.signature)
formData.append('file', blob, uniqueName)
const xhr = new XMLHttpRequest()
xhr.open('POST', aliyunKey.host, true)
// 监听上传进度
xhr.upload.onprogress = (event) => {
if (event.lengthComputable && onProgress) {
const percent = (event.loaded / event.total) * 100
onProgress(Number.parseFloat(percent.toFixed(2))) // 保留两位小数
updateUploadProgress(percent) // 更新进度条
}
}
xhr.onload = async () => {
if (xhr.status === 204 || xhr.status === 200) {
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`
await addFileApi({
fileName,
fileSize,
fileMapName: allFilePath,
})
updateUploadProgress(100) // 上传完毕
ElMessage.success('上传成功')
setTimeout(() => {
closeUploadProgress() // 关闭上传进度条
}, 500)
resolve({
url: allFilePath,
fileName,
fileSize,
})
}
else {
updateUploadProgress(0, 'failed') // 上传失败
ElMessage.error('上传失败,请稍后再试')
setTimeout(() => {
closeUploadProgress() // 关闭上传进度条
}, 500)
reject(new Error(`OSS上传失败: ${xhr.responseText}`))
}
}
xhr.onerror = () => {
updateUploadProgress(0, 'failed') // 上传失败
ElMessage.error('上传失败,请稍后再试')
setTimeout(() => {
closeUploadProgress() // 关闭上传进度条
}, 500)
reject(new Error(`OSS上传异常: ${xhr.responseText}`))
}
xhr.send(formData)
}
catch (error) {
updateUploadProgress(0, 'failed') // 上传失败
ElMessage.error('上传失败,请稍后再试')
setTimeout(() => {
closeUploadProgress() // 关闭上传进度条
}, 500)
reject(error)
}
})
.catch(reject)
})
}
@@ -134,6 +134,7 @@ function onSubmit() {
display: flex;
height: 100vh;
overflow: hidden;
background-color: #fff;
.auth-bg {
width: 70%;
@@ -351,7 +351,7 @@ function navigateTo(path: string) {
display: flex;
height: 100vh;
overflow: hidden;
background-color: #fff;
.auth-bg {
width: 70%;
height: 100%;
@@ -0,0 +1,235 @@
<script lang="ts" setup>
import type { CompanyDetail } from '@/types/company'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import WangEditor from '@/components/wang-editor/index.vue'
import { getCompanyDetailApi } from '@/request/api/company'
const route = useRoute()
const router = useRouter()
const companyId = ref<number>(0)
const companyDetail = ref<CompanyDetail>({
id: 0,
name: '',
areas: [],
industries: [],
logo: '',
profile: '',
phone: '',
email: '',
description: '',
users: [],
})
onMounted(() => {
companyId.value = Number(route.query.id) || 0
if (!companyId.value) {
router.push('/')
return
}
getCompanyDetailApi(companyId.value).then((res) => {
if (res.isSuccess) {
companyDetail.value = res.data
}
else {
ElMessage.error(res.message || '加载公司信息失败,请稍后再试')
router.push('/')
}
}).catch((err) => {
console.log(err)
ElMessage.error('加载公司信息失败,请稍后再试')
})
})
</script>
<template>
<div class="company-detail-page">
<div class="detail-container">
<div class="header-region">
<el-avatar shape="square" :size="64" class="logo" :src="companyDetail.logo || '/no-avatar.png'" />
<div class="info">
<div class="title">
<span>{{ companyDetail.name }}</span>
</div>
<div class="tag-section">
<el-tag v-for="item in companyDetail.industries" :key="item" type="primary">
{{ item }}
</el-tag>
</div>
</div>
</div>
<div class="info-region">
<div id="basic" class="info-item">
<div class="info-header">
<span class="info-title">基础信息</span>
</div>
<el-descriptions border>
<el-descriptions-item label="电话">
{{ companyDetail.phone || '-' }}
</el-descriptions-item>
<el-descriptions-item label="邮箱">
{{ companyDetail.email || '-' }}
</el-descriptions-item>
<el-descriptions-item label="成立日期">
-
</el-descriptions-item>
<el-descriptions-item label="区域">
{{ companyDetail.areas.join('/') || '-' }}
</el-descriptions-item>
<el-descriptions-item label="详细地址" :span="2">
-
</el-descriptions-item>
</el-descriptions>
</div>
<div id="profile" class="info-item">
<div class="info-header">
<span class="info-title">公司简介</span>
</div>
<span class="company-profile">
{{ companyDetail.profile || '-' }}
</span>
</div>
<div id="users" class="info-item">
<div class="info-header">
<span class="info-title">公司成员</span>
</div>
<el-table :data="companyDetail.users" style="width: 100%" stripe border>
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="position" label="职务" width="180" />
<el-table-column prop="phone" label="手机号" width="180" />
<el-table-column prop="email" label="邮箱号" width="180" />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default>
<el-button type="primary" size="small" text bg>
发起聊天
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div id="description" class="info-item">
<div class="info-header">
<span class="info-title">公司详细介绍</span>
</div>
<WangEditor v-model="companyDetail.description" mode="view" />
</div>
</div>
</div>
<div class="anchor-container">
<el-affix :offset="80">
<div class="anchor-title">
导航
</div>
<el-anchor :offset="70">
<el-anchor-link href="#basic">
基础信息
</el-anchor-link>
<el-anchor-link href="#profile">
公司简介
</el-anchor-link>
<el-anchor-link href="#users">
公司成员
</el-anchor-link>
<el-anchor-link href="#description">
公司详细介绍
</el-anchor-link>
</el-anchor>
</el-affix>
</div>
</div>
</template>
<style lang="scss" scoped>
.company-detail-page {
width: 100%;
display: flex;
justify-content: center;
padding: 48px 0px;
.detail-container {
width: 1250px;
.header-region {
padding: 20px;
background-color: #fff;
display: flex;
.info {
margin-left: 16px;
.title {
font-weight: bold;
font-size: 22px;
}
.tag-section {
margin-top: 4px;
> * {
margin-right: 16px;
}
}
}
}
.info-region {
margin-top: 36px;
background-color: #fff;
padding: 16px;
.info-item {
margin-bottom: 24px;
:deep(.el-table__header) {
.el-table__cell {
background-color: #f5f7fa;
}
}
}
.info-header {
height: 32px;
margin-bottom: 10px;
.info-title {
font-weight: 600;
font-size: 18px;
}
}
.company-profile {
word-break: break-all;
color: #333;
font-size: 14px;
line-height: 1.6;
}
}
}
.anchor-container {
min-width: 200px;
margin-left: 40px;
.anchor-title {
background-color: #fff;
font-weight: 600;
font-size: 14px;
line-height: 30px;
padding-left: 14px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
:deep(.el-anchor) {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
}
}
</style>
@@ -1,23 +1,275 @@
<script lang="ts" setup>
import type { CompanyListItem } from '@/types/company'
import { ElMessage } from 'element-plus'
import { onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import QueryCompany from '@/components/QueryCompany.vue'
import { queryCompanyApi } from '@/request/api/company'
import { useCommonStore } from '@/store/common'
const router = useRouter()
const commonStore = useCommonStore()
const page = reactive<Pagination>({
current: 1,
pageSize: 10,
total: 0,
})
const loading = ref<boolean>(true)
const companyList = ref<CompanyListItem[]>([])
onMounted(() => {
getCompanyList()
})
function getCompanyList() {
loading.value = true
queryCompanyApi({
currentPage: page.current,
pageSize: page.pageSize,
areas: commonStore.companyQuery.areas.map((item: string[]) => item.join(',')),
industries: commonStore.companyQuery.industries,
name: commonStore.companyQuery.name,
}).then((res) => {
if (res.isSuccess) {
companyList.value = res.data.records
page.total = res.data.total
}
else {
ElMessage.error(res.message || '加载失败,请稍后再试')
}
}).catch((err) => {
console.log(err)
ElMessage.error('加载失败,请稍后再试')
}).finally(() => {
loading.value = false
})
}
function toDetail(data: CompanyListItem) {
router.push({
path: '/company/detail',
query: {
id: data.id,
},
})
}
</script>
<template>
<div class="wrapper">
<div class="query">
<QueryCompany style="width: 1200px;" />
<div class="company-wrapper">
<div class="company-container">
<QueryCompany @search="getCompanyList()" />
<div class="list-container">
<div class="list-header">
<div class="search-title">
为您找到
<span>
{{ page.total }}
</span>
条相关企业
</div>
</div>
<div class="company-list">
<div v-for="item in companyList" :key="item.id" class="company-item">
<el-avatar shape="square" :src="item.logo || '/no-avatar.png'" :size="70" class="company-logo" />
<div class="company-info">
<div class="company-header">
<div class="company-name">
{{ item.name }}
</div>
</div>
<div class="company-tags">
<el-tag v-for="tag in item.industries" :key="tag" type="primary" effect="dark">
{{ tag }}
</el-tag>
</div>
<p class="company-profile">
{{ item.profile || '-' }}
</p>
<div class="company-footer">
<div class="company-details">
<div class="detail-item">
<i-material-symbols:location-on />
<span>{{ item.areas.join('/') || '___' }}</span>
</div>
<div class="detail-item">
<i-material-symbols:mail />
<span>{{ item.email || '___' }}</span>
</div>
<div class="detail-item">
<i-material-symbols:call />
<span>{{ item.phone || '___' }}</span>
</div>
</div>
<div class="company-actions">
<el-button @click="toDetail(item)">
<i-ri:information-2-line />
<span class="button-text">
详细
</span>
</el-button>
<el-button type="primary">
<i-ri:message-3-fill />
<span class="button-text">
发起聊天
</span>
</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="company-pagination">
<el-pagination
v-model:current-page="page.current"
:page-size="page.pageSize"
:total="page.total"
layout="prev, pager, next"
background
size="large"
/>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.wrapper {
.company-wrapper {
width: 100%;
.query {
display: flex;
justify-content: center;
.company-container {
padding: 48px 0px;
width: 1250px;
}
.list-container {
display: flex;
flex-direction: column;
margin-top: 36px;
.list-header {
padding: 16px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f1f1f1;
background-color: #fff;
.search-title {
font-weight: bold;
span {
color: red;
}
}
}
}
.company-list {
display: flex;
flex-direction: column;
.company-item {
background-color: #fff;
border-radius: 4px;
padding: 13px 26px;
display: flex;
align-items: center;
border-bottom: 1px solid #e0e0e0;
&:hover {
background-color: #f2f8fe;
.company-name {
color: var(--el-color-primary) !important;
}
}
.company-logo {
flex-shrink: 0;
margin-right: 20px;
}
.company-info {
flex: 1;
.company-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
.company-name {
font-size: 20px;
font-weight: 600;
color: #1e293b;
cursor: pointer;
}
}
.company-tags {
margin-bottom: 6px;
> * {
margin-right: 16px;
}
}
.company-profile {
color: #64748b;
line-height: 1.6;
margin-bottom: 8px;
font-size: 14px;
}
.company-footer {
display: flex;
justify-content: space-between;
align-items: center;
.company-details {
display: flex;
color: #64748b;
font-size: 13px;
.detail-item {
display: flex;
align-items: center;
margin-right: 16px;
span {
margin-left: 4px;
}
}
}
.company-actions {
display: flex;
> * {
margin-left: 12px;
}
.button-text {
margin-left: 4px;
}
}
}
}
}
}
.company-pagination {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
margin: 16px 0px;
}
}
</style>
@@ -127,7 +127,6 @@ defineProps({
}
.area-row:hover {
background-color: #f9f9fb;
}
.area-row:last-child {
@@ -139,7 +138,7 @@ defineProps({
align-items: center;
justify-content: center;
width: 15%;
background-color: #f8f9fa;
background-color: #fcfcfd;
color: #34495e;
font-weight: bold;
border-right: 1px solid #e0e3e8;
@@ -0,0 +1,12 @@
<script lang="ts" setup>
</script>
<template>
<div class="">
settings
</div>
</template>
<style lang="scss" scoped>
//
</style>
File diff suppressed because it is too large. Load diff