Compare commits

...

92 Commits

Author SHA1 Message Date
a12afc6bc1 优化kl-card-picture组件文本颜色样式 2025-10-16 23:09:12 +08:00
ae57f28357 优化排行榜组件并添加全局错误处理 2025-10-16 22:40:19 +08:00
3265c00fba feat: 启用排行榜组件并优化微信登录参数 2025-10-16 20:13:58 +08:00
ab92461635 优化微信扫码登录openId字段命名 2025-10-15 22:49:48 +08:00
3c6ed5a72c 优化微信扫码登录功能及token获取逻辑 2025-10-15 22:40:23 +08:00
9e225417a6 优化微信扫码登录功能实现 2025-10-15 22:27:12 +08:00
94f1828620 优化微信扫码登录组件UI及交互 2025-10-14 22:15:46 +08:00
58d3f2e890 feat: 添加微信授权成功通知功能 2025-10-14 08:58:36 +08:00
5baae7652f feat: 添加微信扫码登录功能 2025-10-13 23:03:55 +08:00
3f3ea878b9 优化提现手续费动态配置 2025-10-08 22:22:54 +08:00
89f3b9679d 优化交易中心UI展示 2025-10-08 21:16:07 +08:00
b0e5244a79 feat: 统一路由路径规范 2025-10-08 21:12:51 +08:00
f8176abaad 优化收益展示字段及数值 2025-10-08 20:50:30 +08:00
575f6fa2f1 优化VIP价格显示及移除工具函数 2025-10-08 20:39:51 +08:00
5ee69038fa 优化聊天页面UI及API接口调用 2025-09-30 22:20:07 +08:00
2bc5a11946 优化热门绘画组件查询参数处理 2025-09-29 09:37:36 +08:00
b23a85b9ec 优化首页组件代码及调试信息 2025-09-29 09:12:34 +08:00
f2c4d14007 feat: sosososs 2025-09-27 21:59:11 +08:00
82b6f4d63b feat: sosososs 2025-09-27 20:36:51 +08:00
d995ac2b37 feat: sosososs 2025-09-27 19:57:02 +08:00
01392a6329 feat: sosososs 2025-09-27 19:18:52 +08:00
689d12e632 feat: sosososs 2025-09-27 19:09:46 +08:00
8c50ffd479 优化评论功能API接口参数处理 2025-09-26 23:06:31 +08:00
ca7982c974 优化工具箱详情页评论功能及API接口 2025-09-26 22:13:28 +08:00
6c85256b96 优化详情页功能及API接口参数 2025-09-26 21:47:51 +08:00
972bd2c8b8 优化个人中心交易记录显示 2025-09-25 22:12:36 +08:00
ecf120221f 优化工具箱页面分类组件及交互功能 2025-09-25 22:10:26 +08:00
30fd03590c 优化API接口类型修改downloadId字段类型 2025-09-25 20:37:25 +08:00
38fc29ccaa 优化工具箱详情页面及API接口类型 2025-09-24 22:42:52 +08:00
70a75333e8 优化VIP卡片布局及工具箱详情页面 2025-09-24 22:03:23 +08:00
92ca0a4418 Merge branch 'main' of https://git.tuxixi.net/wangqiao/front-pc 2025-09-24 21:05:36 +08:00
6a002ceb16 优化工具箱详情页面移除冗余日志输出 2025-09-24 21:05:28 +08:00
7f7664e68f 优化侧边菜单样式内边距 2025-09-24 08:59:43 +08:00
6f58ba2389 优化工具箱详情页及API接口 2025-09-23 23:14:17 +08:00
33430e0888 优化详情页面包屑显示及ID字段 2025-09-23 22:37:51 +08:00
5b498724c4 优化推荐功能新增参数配置及上传工具 2025-09-23 22:19:33 +08:00
aef8799652 优化推荐功能新增参数配置 2025-09-23 21:34:42 +08:00
bf189f7f5b 优化工具箱详情页面样式及交互功能 2025-09-18 22:44:00 +08:00
06b60a4ff9 优化工具箱详情页面及点击跳转功能 2025-09-16 22:37:41 +08:00
c11116d9a9 优化个人中心头像更新提示文案 2025-09-16 22:07:36 +08:00
48d4ede98e 优化频道内容显示条件判断 2025-09-15 22:17:11 +08:00
fd31274a21 优化帖子删除接口及按钮事件冒泡处理 2025-09-15 22:16:12 +08:00
ec5cddae61 优化群组成员获取接口请求方法 2025-09-15 22:13:09 +08:00
e361ff9c79 feat: sosoos 2025-09-15 21:40:31 +08:00
c93cfeb266 优化缓存标识前缀区分模块 2025-09-15 21:37:32 +08:00
4b36bc2e06 优化个人中心提现管理界面样式 2025-09-15 21:34:05 +08:00
ce3aab1c76 优化个人中心表单必填项验证 2025-09-15 21:26:57 +08:00
0efb671bff 优化工具箱创建接口路径 2025-09-15 11:58:14 +08:00
c0d41b4d8d 优化BannerTips客服联系功能 2025-09-14 21:44:01 +08:00
394df57af1 优化工具箱分页参数及接口路径 2025-09-14 21:13:42 +08:00
ab57b6c9b2 优化邮箱验证码发送接口 2025-09-14 20:45:43 +08:00
87ce756f6b 优化邮箱验证码发送接口 2025-09-14 20:39:59 +08:00
9d2863d6d3 优化工具箱分类筛选功能 2025-09-14 19:34:54 +08:00
8677405266 feat: soso 2025-09-14 19:27:36 +08:00
a8b55412c6 优化个人中心地址选择功能 2025-09-14 17:35:47 +08:00
cc2f0d5eeb 优化工具箱分类筛选功能 2025-09-14 17:23:53 +08:00
9c62a6a198 优化用户注销功能及token处理逻辑 2025-09-14 17:02:57 +08:00
b1174fc1e3 优化工具发布分类及来源类型 2025-09-14 16:47:22 +08:00
e6c99fbbca 优化工具发布分类选择组件 2025-09-14 16:29:00 +08:00
239a1272b2 优化工具发布分类功能及参数 2025-09-14 16:22:30 +08:00
0d4c625b10 优化工具发布分类类型参数 2025-09-14 11:21:07 +08:00
dc824592ce 优化用户注销功能及逻辑处理 2025-09-14 11:17:46 +08:00
d096ebb83c 优化账号绑定功能及消息提示组件 2025-09-14 10:55:19 +08:00
a0a44b4551 优化账号绑定功能及社交解绑 2025-09-14 10:41:15 +08:00
cef6c8c341 优化图纸编辑功能和地址联动逻辑 2025-09-14 09:58:12 +08:00
9d4dda04c9 优化个人中心账号绑定功能 2025-09-13 22:43:38 +08:00
8754d3a333 优化工具发布表单和描述字数限制 2025-09-13 21:36:10 +08:00
8d9bc93955 优化TDK数据获取逻辑和空值处理 2025-09-13 13:49:22 +08:00
1e292102d1 优化个人中心表格字体样式 2025-09-13 13:42:52 +08:00
9417601ab1 优化个人中心表格样式和字体大小 2025-09-13 12:53:55 +08:00
2901b24f43 优化图纸编辑功能和提交逻辑 2025-09-13 12:51:48 +08:00
f3fb25349b 优化图纸编辑功能和提交逻辑 2025-09-13 12:47:10 +08:00
ad61430545 优化图纸预览和编辑功能 2025-09-13 11:50:44 +08:00
164690bcce 优化个人中心表格显示和操作功能 2025-09-13 10:17:32 +08:00
2ac31bc1a3 优化个人中心表单验证和路由跳转 2025-09-13 09:44:30 +08:00
41ff1b8f44 优化导航栏样式和间距调整 2025-09-12 08:50:27 +08:00
9ac4fa6e5d 优化上传表格组件显示和新增工具箱选项 2025-09-11 22:31:03 +08:00
0bc2bdb9bb 优化用户中心VIP图标显示位置 2025-09-11 21:43:17 +08:00
4db377161c 优化用户中心VIP图标位置和积分文案 2025-09-11 21:39:12 +08:00
a60b28aa22 优化账户安全表单样式调整 2025-09-11 21:25:14 +08:00
fec929bf06 refactor: 优化个人中心账户管理功能 2025-09-11 21:21:56 +08:00
b0b50ed960 优化用户头像样式和间距调整 2025-09-10 21:51:54 +08:00
78939951d9 feat: 更新公安备案链接并添加跳转功能 2025-09-10 21:46:27 +08:00
02bc9c00b0 feat: 更新页脚样式并添加公安备案信息 2025-09-10 21:35:29 +08:00
823e3d9f99 修复文件列表显示逻辑,使用otherFiles替代files 2025-09-09 11:05:07 +08:00
a1735a5e94 优化预览组件尺寸与图片展示 2025-09-08 10:31:28 +08:00
7839fa565e 更新用户头像和表单字数限制 2025-09-08 10:15:32 +08:00
9054376279 附件上传表单验证优化 2025-09-08 10:05:24 +08:00
3ae61916ca Merge branch 'main' of https://git.tuxixi.net/wangqiao/front-pc 2025-09-08 10:01:18 +08:00
1a86b4cb7e 添加项目版本号1.0.0 2025-09-08 10:00:52 +08:00
7a33f67aed feat: 添加通知列表功能和样式优化 2025-09-07 22:30:20 +08:00
9f5942546d refactor: 优化请求封装和用户状态管理 2025-09-07 15:26:01 +08:00
78 changed files with 2038 additions and 413 deletions

View File

@ -49,7 +49,7 @@ export const getChannelPosts = (params: { id: number }) => {
* @return {Promise} * @return {Promise}
*/ */
export const postsDelete = (params: { id: number }) => { export const postsDelete = (params: { id: number }) => {
return useDollarFetchRequest.del<IResponse<boolean>>('/prod-api/app-api/business/posts/delete', { params }) return useDollarFetchRequest.del<IResponse<boolean>>('/prod-api/app-api/business/posts/delete?id=' + params.id, {})
} }
/** /**
* 获取帖子详情 * 获取帖子详情
@ -64,7 +64,7 @@ export const getChannelDetail = (params: { id: string }) => {
* @return {Promise} * @return {Promise}
*/ */
export const postscommentpage = (params: { postsId: string; pageNo: number; pageSize: number }) => { export const postscommentpage = (params: { postsId: string; pageNo: number; pageSize: number }) => {
return useFetchRequest.get<IResponse<PageResultPostsCommentRespVO>>('/prod-api/app-api/business/posts-comment/page', { query: params }) return useDollarFetchRequest.get<IResponse<PageResultPostsCommentRespVO>>('/prod-api/app-api/business/posts-comment/page', { query: params })
} }
/** /**
* 创建帖子评论 * 创建帖子评论
@ -147,5 +147,5 @@ export const deleteChannelFollow = (params: { channelId: string }) => {
* 根据群组ID获取群组成员 * 根据群组ID获取群组成员
*/ */
export const getGroupMembers = (params: { channelId: string }) => { export const getGroupMembers = (params: { channelId: string }) => {
return useFetchRequest.get<IResponse<MemberUserRespDTO[]>>(`/prod-api/app-api/mqtt/session/users/${params.channelId}`) return useDollarFetchRequest.get<IResponse<MemberUserRespDTO[]>>(`/prod-api/app-api/mqtt/session/users/${params.channelId}`)
} }

View File

@ -7,22 +7,22 @@ import type { ProjectRespVO, PageResultProjectCommentResVO, ProjectDrawPageRespV
* @return {Promise} * @return {Promise}
*/ */
export const getDetail = (params: { id?: number | string }) => { export const getDetail = (params: { id?: number | string }) => {
return useFetchRequest.get<IResponse<ProjectRespVO>>('/prod-api/app-api/business/app/project-draw/preview', { query:params }) return useFetchRequest.get<IResponse<ProjectRespVO>>('/prod-api/app-api/business/app/project-draw/preview', { query: params })
} }
/** /**
* 获取评论列表 * 获取评论列表
* @return {Promise} * @return {Promise}
*/ */
export const getCommentList = (params: { relationId?: number | string; pageNum?: number; pageSize?: number }) => { export const getCommentList = (params: { relationId?: number | string; pageNum?: number; pageSize?: number; type: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultProjectCommentResVO>>('/prod-api/app-api/business/app/project-comment/page', { query:params }) return useDollarFetchRequest.get<IResponse<PageResultProjectCommentResVO>>('/prod-api/app-api/business/app/project-comment/page', { query: params })
} }
/** /**
* 发表评论 * 发表评论
* @return {Promise} * @return {Promise}
*/ */
export const createComment = (params: { relationId?: number | string; content?: string; projectId?: number | string }) => { export const createComment = (params: { relationId?: number | string; content?: string; projectId?: number | string; type: number }) => {
return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/app/project-comment/create', params) return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/app/project-comment/create', params)
} }
@ -31,14 +31,14 @@ export const createComment = (params: { relationId?: number | string; content?:
* @return {Promise} * @return {Promise}
*/ */
export const getRelationRecommend = (params: { type?: number | string; projectType?: number | string }) => { export const getRelationRecommend = (params: { type?: number | string; projectType?: number | string }) => {
return useFetchRequest.get<IResponse<ProjectDrawPageRespVO[]>>('/prod-api/app-api/business/app/project-draw/top-list', { query:params }) return useFetchRequest.get<IResponse<ProjectDrawPageRespVO[]>>('/prod-api/app-api/business/app/project-draw/top-list', { query: params })
} }
/** /**
* 举报 * 举报
* @return {Promise} * @return {Promise}
*/ */
export const report = (params: { id?: number | string; title?: string; comments?: string; files?: any; projectId: any; drawId: any }) => { export const report = (params: { id?: number | string; title?: string; comments?: string; files?: any; projectId?: any; drawId: any; type: any }) => {
return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/project-report/create', params) return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/project-report/create', params)
} }
@ -50,6 +50,14 @@ export const getUserInfo = (params: { id?: number | string }) => {
return useFetchRequest.get<IResponse<UserExtendSimpleRespDTO>>('/prod-api/app-api/business/app/project-draw/preview-user-info', { params }) return useFetchRequest.get<IResponse<UserExtendSimpleRespDTO>>('/prod-api/app-api/business/app/project-draw/preview-user-info', { params })
} }
/**
* 获取工具发布人信息
*/
export const getToolUserInfo = (params: { id?: number | string }) => {
return useFetchRequest.get<IResponse<UserExtendSimpleRespDTO>>('/prod-api/app-api/business/resource/publish-user-info', { params })
}
/** /**
* 当前用户的主要作品内容 * 当前用户的主要作品内容
*/ */
@ -59,7 +67,7 @@ export const getMainWork = (params: { id?: number | string; limit: number; membe
/** /**
* 创建内容信息 * 创建内容信息
*/ */
export const createContent = (params: { projectId: any; drawId: any }) => { export const createContent = (params: { projectId?: any; drawId: any; type: any }) => {
return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/project-member-favorites/create', params) return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/business/project-member-favorites/create', params)
} }

View File

@ -35,6 +35,7 @@ export interface ProjectRespVO {
projectTypeName: string projectTypeName: string
favoriteId?: string favoriteId?: string
relationDraws: RelationDraws[] relationDraws: RelationDraws[]
no?: string
filesInfo: { filesInfo: {
fileSize: string fileSize: string
count: number count: number
@ -136,6 +137,7 @@ export interface UserExtendSimpleRespDTO {
files: any[] files: any[]
fansCount: number fansCount: number
projectCount: number projectCount: number
postsNum?: number
} }
export interface ProjectDrawMemberRespVO { export interface ProjectDrawMemberRespVO {

View File

@ -103,4 +103,11 @@ export const getTDK = () => {
*/ */
export const getTDKList = () => { export const getTDKList = () => {
return useFetchRequest.get<IResponse<TdkSettingsDO[]>>('/prod-api/app-api/business/tdk-settings/list-menu', {}) return useFetchRequest.get<IResponse<TdkSettingsDO[]>>('/prod-api/app-api/business/tdk-settings/list-menu', {})
}
/**
* 通知列表
*/
export const getNoticeList = () => {
return useDollarFetchRequest.get<IResponse<any>>('/prod-api/app-api/system/index-setting/notice-list', {})
} }

View File

@ -27,8 +27,18 @@ export const loginByMobile = (params: { mobile: string; code: string; socialCode
/** /**
* 发送邮箱验证码 * 发送邮箱验证码
*/ */
export const sendEmailCode = (params: { email: string }) => { export const sendEmailCode = (data: { email: string }) => {
return useDollarFetchRequest.post<IResponse<any>>('/prod-api/app-api/member/auth/send-email-code', params) return useDollarFetchRequest.post<IResponse<any>>(
'/prod-api/app-api/member/auth/send-email-code?email=' + data.email,
{},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json, text/plain, */*',
'Access-Control-Allow-Origin-Type': '*',
},
}
)
} }
/** /**
@ -44,3 +54,10 @@ export const loginByEmail = (params: { email: string; code: string }) => {
export const resetPassword = (params: { password: string; code: string }) => { export const resetPassword = (params: { password: string; code: string }) => {
return useDollarFetchRequest.put<IResponse<boolean>>('/prod-api/app-api/member/user/update-password', params) return useDollarFetchRequest.put<IResponse<boolean>>('/prod-api/app-api/member/user/update-password', params)
} }
/**
* 授权成功通知后台
*/
export const notifyAuthSuccess = (params: { code: string; state: string }) => {
return useDollarFetchRequest.get<IResponse<any>>('/prod-api/app-api/member/auth/wx-login-url', { query: params })
}

View File

@ -36,26 +36,26 @@ export const createOrder = (params: { spuId: number }) => {
* 获得钱包充值套餐列表 * 获得钱包充值套餐列表
*/ */
export const listWalletRechargePackage = () => { export const listWalletRechargePackage = () => {
return useDollarFetchRequest.get<IResponse<AppPayWalletPackageRespVO[]>>('/prod-api/app-api/pay/wallet-recharge-package/list', {}) return useDollarFetchRequest.get<IResponse<AppPayWalletPackageRespVO[]>>('/prod-api/app-api/pay/wallet-recharge-package/list', {})
} }
/** /**
* 获取支付状态 * 获取支付状态
*/ */
export const getPayStatus = (params: { id: number }) => { export const getPayStatus = (params: { id: number }) => {
return useDollarFetchRequest.get<IResponse<PayOrderRespVO>>('/prod-api/app-api/pay/order/get', {query:params}) return useDollarFetchRequest.get<IResponse<PayOrderRespVO>>('/prod-api/app-api/pay/order/get', { query: params })
} }
/** /**
* 通过code获取token * 通过code获取token
*/ */
export const getTokenByCode = (params: { type: number; code: string; state: string }) => { export const getTokenByCode = (params: { type: number; code: string; state: string }) => {
return useDollarFetchRequest.post<IResponse<string>>('/prod-api/app-api/member/auth/token-by-code', params) return useDollarFetchRequest.post<IResponse<string>>('/prod-api/app-api/member/auth/token-by-code', params)
} }
/** /**
* 社交快捷登录,使用 code 授权码 * 社交快捷登录,使用 code 授权码
*/ */
export const socialLoginByCode = (params: { type: number; code: string; state: string }) => { export const socialLoginByCode = (params: { type?: number; code?: string; state?: string; openId?: string; sceneStr?: string }) => {
return useDollarFetchRequest.post< return useDollarFetchRequest.post<
IResponse<{ IResponse<{
accessToken: string accessToken: string
@ -71,5 +71,5 @@ export const socialLoginByCode = (params: { type: number; code: string; state: s
* 获得钱包充值记录分页 * 获得钱包充值记录分页
*/ */
export const getWalletRechargeRecordPage = (params: { pageNo: number; pageSize: number }) => { export const getWalletRechargeRecordPage = (params: { pageNo: number; pageSize: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultAppPayWalletRechargeRespVO>>('/prod-api/app-api/pay/wallet-transaction/page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultAppPayWalletRechargeRespVO>>('/prod-api/app-api/pay/wallet-transaction/page', { query: params })
} }

View File

@ -43,7 +43,7 @@ export const updateUserExtend = (params: UserExtendSaveReqVO) => {
* @returns * @returns
*/ */
export const getUserAuthInfo = () => { export const getUserAuthInfo = () => {
return useFetchRequest.get<IResponse<UserAuthInfoRespVO>>('/prod-api/app-api/member/user-auth-info/get', {}) return useDollarFetchRequest.get<IResponse<UserAuthInfoRespVO>>('/prod-api/app-api/member/user-auth-info/get', {})
} }
/** /**
* 创建用户信息 * 创建用户信息
@ -66,13 +66,13 @@ export const updateUserAuthInfo = (params: UserAuthInfoRespVO) => {
* 获得内容信息分页 * 获得内容信息分页
*/ */
export const getContentPage = (params: { type: number }) => { export const getContentPage = (params: { type: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/project-history/page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/project-history/page', { query: params })
} }
/** /**
* 获得用户项目工具箱下载分页 * 获得用户项目工具箱下载分页
*/ */
export const getUserToolBoxPage = (params: { pageNum: number; pageSize: number; type?: number }) => { export const getUserToolBoxPage = (params: { pageNum: number; pageSize: number; type?: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/project-member-file/page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/project-member-file/page', { query: params })
} }
/** /**
@ -92,20 +92,20 @@ export const signIn = () => {
* 获得用户积分记录分页 * 获得用户积分记录分页
*/ */
export const getUserPointPage = (params: { pageNo: number; pageSize: number }) => { export const getUserPointPage = (params: { pageNo: number; pageSize: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultMemberPointRecordRespVO>>('/prod-api/app-api/member/point/record/page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultMemberPointRecordRespVO>>('/prod-api/app-api/member/point/record/page', { query: params })
} }
/** /**
* 近期收益和近期活跃 * 近期收益和近期活跃
*/ */
export const getRecentIncomeAndActive = (params: { type: number; limit: number }) => { export const getRecentIncomeAndActive = (params: { type: number; limit: number }) => {
return useDollarFetchRequest.get<IResponse<UserStatisticsLineRespVO>>('/prod-api/app-api/member/statistics/line', {query:params}) return useDollarFetchRequest.get<IResponse<UserStatisticsLineRespVO>>('/prod-api/app-api/member/statistics/line', { query: params })
} }
/** /**
* *
资源下载分布 资源下载分布
*/ */
export const getResourceDistribution = (params: { type: number; limit: number }) => { export const getResourceDistribution = (params: { type: number; limit: number }) => {
return useDollarFetchRequest.get<IResponse<UserStatisticsBarRespVO>>('/prod-api/app-api/member/statistics/bar', {query:params}) return useDollarFetchRequest.get<IResponse<UserStatisticsBarRespVO>>('/prod-api/app-api/member/statistics/bar', { query: params })
} }
/** /**
* 我的数据统计 包括我的金币 我的关注 我的发布等等 * 我的数据统计 包括我的金币 我的关注 我的发布等等
@ -118,14 +118,16 @@ export const getUserStatistics = () => {
* 获得项目订单用户收藏信息分页 * 获得项目订单用户收藏信息分页
*/ */
export const getUserFavoritePage = (params: { pageNo: number; pageSize: number; userId: any; type: number }) => { export const getUserFavoritePage = (params: { pageNo: number; pageSize: number; userId: any; type: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultProjectMemberFavoritesRespVO>>('/prod-api/app-api/business/project-member-favorites/page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultProjectMemberFavoritesRespVO>>('/prod-api/app-api/business/project-member-favorites/page', {
query: params,
})
} }
/*** /***
* 自己发布的-内容信息分页 * 自己发布的-内容信息分页
*/ */
export const getOwnContentPage = (params: { pageNo: number; pageSize: number; type: number }) => { export const getOwnContentPage = (params: { pageNo: number; pageSize: number; type: number }) => {
return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/app/project-draw/my-page', {query:params}) return useDollarFetchRequest.get<IResponse<PageResultProjectHistoryResVO>>('/prod-api/app-api/business/app/project-draw/my-page', { query: params })
} }
/** /**
@ -148,3 +150,49 @@ export const deleteResource = (params: { id: number }) => {
export const getUserExtend = () => { export const getUserExtend = () => {
return useFetchRequest.get<IResponse<UserExtendRespVO>>('/prod-api/app-api/member/user-extend/get', {}) return useFetchRequest.get<IResponse<UserExtendRespVO>>('/prod-api/app-api/member/user-extend/get', {})
} }
/**
* 取消社交绑定
*/
export const cancelSocialBind = (params: { type: number; openid: string }) => {
return useDollarFetchRequest.post<IResponse<boolean>>('/prod-api/app-api/member/social-user/unbind', params)
}
/**
* 用户注销账号
*/
export const userLogout = () => {
return useDollarFetchRequest.del<IResponse<boolean>>('/prod-api/app-api/member/user/unregister-user', {})
}
/**
* 获取钱包配置
*/
export const getWalletConfig = () => {
return useDollarFetchRequest.get<
IResponse<{
rechargeRate: number
commissionRate: number
withdrawRateOfRecharge: number
withdrawRateOfEarn: number
}>
>('/prod-api/app-api/pay/wallet/get-config', {})
}
/**
* 微信登录二维码链接
*/
export const getLoginQrcode = () => {
return useDollarFetchRequest.get<IResponse<{ sceneStr: string; qrCodeUrl: string }>>('/prod-api/app-api/member/auth/wx-login-url', {})
}
/***
* member/auth/checkScanStatus
* 检查扫码登录状态
*/
export const checkScanStatus = (params: { sceneStr: string }) => {
return useDollarFetchRequest.get<IResponse<{ status: string; openId: string | null; message: string }>>('/prod-api/app-api/member/auth/checkScanStatus', {
query: params,
})
}

View File

@ -46,6 +46,8 @@ export interface UserExtendRespVO {
description: string description: string
authStatus: number authStatus: number
createTime: string createTime: string
wxOpenId: string
qqOpenId: string
files: { files: {
id: number id: number
memberId: number memberId: number
@ -153,6 +155,7 @@ export interface UserStatisticsCountRespVO {
currencyCount: number currencyCount: number
previewCount: number previewCount: number
revenueCount: number revenueCount: number
revenueBalance: number
} }
export interface PageResultProjectMemberFavoritesRespVO { export interface PageResultProjectMemberFavoritesRespVO {

View File

@ -1,6 +1,6 @@
import * as useDollarFetchRequest from '~/composables/useDollarFetchRequest' import * as useDollarFetchRequest from '~/composables/useDollarFetchRequest'
import * as useFetchRequest from '~/composables/useFetchRequest' import * as useFetchRequest from '~/composables/useFetchRequest'
import type { TcreateReq, TpageReq, TpageRes } from './types' import type { TcreateReq, TpageReq, TpageRes, ProjectResourceRespVO } from './types'
/** /**
* 新建工具箱 * 新建工具箱
@ -8,12 +8,23 @@ import type { TcreateReq, TpageReq, TpageRes } from './types'
* @returns * @returns
*/ */
export const create = (params: TcreateReq) => { export const create = (params: TcreateReq) => {
return useDollarFetchRequest.post<IResponse<number>>('/prod-api/app-api/business/app/project-resource/create', params) return useDollarFetchRequest.post<IResponse<number>>('/prod-api/app-api/business/resource/create', params)
} }
/*** /***
* 获得内容信息分页 * 获得内容信息分页
*/ */
export const page = (params: TpageReq) => { export const page = (params: any) => {
return useFetchRequest.get<IResponse<TpageRes>>('/prod-api/app-api/business/app/project-resource/page', {query:params}) return useFetchRequest.get<IResponse<TpageRes>>('/prod-api/app-api/business/resource/page', {
query: params,
})
}
/**
* 获得工具箱
*/
export const get = (params: { id: string }) => {
return useFetchRequest.get<IResponse<ProjectResourceRespVO>>('/prod-api/app-api/business/resource/get', {
query: params,
})
} }

View File

@ -6,6 +6,9 @@ export interface TcreateReq {
createAddress?: string createAddress?: string
createIp?: string createIp?: string
projectType: number[] projectType: number[]
categoryId?: number
sourceType?: number
categoryName?: string
files: { files: {
id: number id: number
title: string title: string
@ -59,3 +62,57 @@ export interface TpageItem {
commentsPoint: number commentsPoint: number
ownedUserId: string ownedUserId: string
} }
export interface ProjectResourceRespVO {
id: number
title: string
labels: string[]
createAddress: string
createIp: string
projectType: number[]
categoryId: number
categoryName: string
favoriteId?: number
downloadId?: string
sourceType: number
ownedUserName?: string
ownedUserAvatar?: string
ownedUserIdInfo: {
id: number
nickName: string
avatar: string
}
files: {
id: number
title: string
fileId: number
drawId: number
type: number
url: string
sort: number
size: number
}[]
coverImages: {
id: number
title: string
fileId: number
drawId: number
type: number
url: string
sort: number
size: number
}[]
points: number
createTime: string
updateTime: string
status: number
recommend: boolean
iconUrl: string
hotPoint: number
description: string
previewPoint: number
previewUrl: string
previewImageUrl: string
commentsPoint: number
ownedUserId: string
}

View File

@ -40,7 +40,7 @@ export const indexTabs = () => {
* @returns * @returns
*/ */
export const keywords = (params: { type: string | number; keywords: string }) => { export const keywords = (params: { type: string | number; keywords: string }) => {
return useFetchRequest.get<IResponse<boolean>>('/prod-api/app-api/business/app/dict/label-keywords', {query:params}) return useFetchRequest.get<IResponse<boolean>>('/prod-api/app-api/business/app/dict/label-keywords', { query: params })
} }
/** /**
* 获取格式类型字典信息 * 获取格式类型字典信息
@ -80,3 +80,17 @@ export const homeLabel = () => {
export const getWechat = () => { export const getWechat = () => {
return useDollarFetchRequest.get<IResponse<string>>('/prod-api/app-api/system/index-setting/kefu-wechat') return useDollarFetchRequest.get<IResponse<string>>('/prod-api/app-api/system/index-setting/kefu-wechat')
} }
/**
* 查看图纸
*/
export const view = (params: { id: string | number; projectId: string | number }) => {
return useDollarFetchRequest.get<IResponse<TcreateReq>>('/prod-api/app-api/business/app/project-draw/get', { query: params })
}
/**
* 编辑图纸
*/
export const edit = (data: TcreateReq) => {
return useDollarFetchRequest.put<IResponse<boolean>>('/prod-api/app-api/business/app/project/update', data)
}

View File

@ -61,6 +61,7 @@ export interface pageReq {
createAddress?: string createAddress?: string
createIp?: string createIp?: string
projectType?: any projectType?: any
recommend: boolean // 是否推荐
} }
export interface pageRes { export interface pageRes {
list: { list: {
@ -79,6 +80,7 @@ export interface pageRes {
previewPoint?: number previewPoint?: number
commentsPoint?: number commentsPoint?: number
hotPoint?: number hotPoint?: number
source?: number
}[] }[]
total: number total: number
} }

BIN
assets/images/x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/yuan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/zhuan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,6 +1,8 @@
<template> <template>
<div class="mt-[30px] w-[100%]"> <div class="mt-[30px] w-[100%]">
<div class="h-[48px] w-[100%] rounded-[1px] bg-[#F8F8F8] pl-[10px] text-[16px] text-[#333333] font-normal line-height-[50px]"> 共有{{ result.total || 0 }}条评论 </div> <div class="h-[48px] w-[100%] rounded-[1px] bg-[#F8F8F8] pl-[10px] text-[16px] text-[#333333] font-normal line-height-[50px]">
共有{{ result.total || 0 }}条评论
</div>
<div v-for="item in result.list" :key="item.id" class="mt-[20px] border-b-[1px] border-b-[#eee] border-b-solid pb-[14px]"> <div v-for="item in result.list" :key="item.id" class="mt-[20px] border-b-[1px] border-b-[#eee] border-b-solid pb-[14px]">
<div class="flex items-start"> <div class="flex items-start">
<el-avatar :src="item.creatorInfo.avatar" alt="" srcset="" class="h-[50px] w-[49px] rounded-full" /> <el-avatar :src="item.creatorInfo.avatar" alt="" srcset="" class="h-[50px] w-[49px] rounded-full" />
@ -44,7 +46,7 @@
}, },
projectId: { projectId: {
type: Number, type: Number,
required: true, required: false,
}, },
}) })
@ -66,7 +68,12 @@
// 获取评论列表 // 获取评论列表
const handleGetCommentList = async () => { const handleGetCommentList = async () => {
const res = await getCommentList({ relationId: props.relationId, pageNum: query.value.pageNo, pageSize: query.value.pageSize }) const res = await getCommentList({
relationId: props.relationId,
pageNum: query.value.pageNo,
pageSize: query.value.pageSize,
type: props.projectId ? 1 : 2,
})
if (res.code === 0) { if (res.code === 0) {
result.value.list = res.data.list result.value.list = res.data.list
result.value.total = res.data.total result.value.total = res.data.total
@ -75,7 +82,7 @@
// 发表评论 // 发表评论
const handleCreateComment = async () => { const handleCreateComment = async () => {
const res = await createComment({ relationId: props.relationId, content: commentContent.value, projectId: props.projectId }) const res = await createComment({ relationId: props.relationId, content: commentContent.value, projectId: props.projectId || props.relationId, type: props.projectId ? 1 : 2 })
if (res.code === 0) { if (res.code === 0) {
commentContent.value = '' commentContent.value = ''
query.value.pageNo = 1 query.value.pageNo = 1
@ -87,8 +94,9 @@
() => props.relationId, () => props.relationId,
() => { () => {
handleGetCommentList() handleGetCommentList()
},{ },
immediate: true {
immediate: true,
} }
) )
</script> </script>

View File

@ -1,8 +1,9 @@
<template> <template>
<div class="relative mt-[34px] w-[100%]"> <div class="relative mt-[34px] w-[100%]">
<KlTabBar v-model="query.source" :data="tabBar" /> <KlTabBar v-model="query.source" :data="tabBar" />
<div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal" <div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal">
><span class="color-[#1A65FF]">{{ result?.total }}</span <el-button type="warning" class="mr-4px" @click="handleUpload">上传工具</el-button>
<span class="color-[#1A65FF]">{{ result?.total }}</span
>个筛选结果</div >个筛选结果</div
> >
<div class="content mt-[10px]"> <div class="content mt-[10px]">
@ -22,6 +23,7 @@
import { ref } from 'vue' import { ref } from 'vue'
import type { pageRes, pageReq } from '~/api/upnew/types' import type { pageRes, pageReq } from '~/api/upnew/types'
import emptyImg from '~/assets/images/empty.png' import emptyImg from '~/assets/images/empty.png'
import useUserStore from '~/stores/user'
const query = defineModel<pageReq>('modelValue', { const query = defineModel<pageReq>('modelValue', {
required: true, required: true,
@ -41,10 +43,18 @@
value: 1, value: 1,
}, },
{ {
label: '最新上传', label: '转载分享',
value: 2, value: 2,
}, },
]) ])
const handleUpload = () => {
// 先判断登录
const store = useUserStore()
if (!store.token) {
return ElMessage.error('请先登录')
}
navigateTo('/upnew?drawType=1')
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -4,17 +4,33 @@
<div class="banner-text"> <div class="banner-text">
<h1 class="title">开启 CAD 学习之旅</h1> <h1 class="title">开启 CAD 学习之旅</h1>
<p class="subtitle">为你的创意引擎注入强劲动力驱动设计梦想在市场中乘风破浪</p> <p class="subtitle">为你的创意引擎注入强劲动力驱动设计梦想在市场中乘风破浪</p>
<button class="join-button">快来加入</button> <button class="join-button" @click="handleService">客服联系</button>
</div> </div>
<div class="banner-image"> <div class="banner-image">
<img src="~/assets/images/foreign_banner.png" alt="CAD工作环境" /> <img src="~/assets/images/foreign_banner.png" alt="CAD工作环境" />
</div> </div>
</div> </div>
</div> </div>
<!-- 打开客服弹窗 弄成组件 -->
<KlService v-if="dialogVisible" v-model:dialog-visible="dialogVisible"></KlService>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useUserStore from '~/stores/user'
import KlService from '~/components/kl-quick-menu/components/kl-service.vue'
// 组件逻辑可以在这里添加 // 组件逻辑可以在这里添加
const dialogVisible = ref(false)
const handleService = () => {
// 判断是否登录
const userStore = useUserStore()
if (!userStore.token) {
ElMessage.error('请先登录')
return
}
dialogVisible.value = true
// 读取未读消息
// readCount.value = false
}
</script> </script>
<style scoped> <style scoped>

View File

@ -6,12 +6,17 @@
<div class="box-border p-[16px]"> <div class="box-border p-[16px]">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<div class="title mr-[38px] text-[16px] text-[#333333] font-bold">{{ props.itemInfo.title }}</div> <div class="title mr-[38px] text-[16px] text-[#333333] font-bold flex items-center" :title="props.itemInfo.title">
<div class="mt-[8px] text-[15px] text-[#999999] font-normal">by {{ props.itemInfo?.ownedUserIdInfo?.nickName }}</div> <img v-if="props.itemInfo.source === 2" src="~/assets/images/zhuan.png" alt="" srcset="" class="mr-[2px] w-[22px] relative bottom-[-4px]" />
<img v-if="props.itemInfo.source === 1" src="~/assets/images/yuan.png" alt="" srcset="" class="mr-[2px] w-[20px] relative bottom-[-4px]" />
{{ props.itemInfo.title }}
</div>
<div class="mt-[8px] text-[15px] text-[#666] font-normal">by {{ props.itemInfo?.ownedUserIdInfo?.nickName }}</div>
<div class="mt-[4px] text-[13px] text-[#999999] font-normal">{{ dayjs(props.itemInfo.createTime).format('YYYY-MM-DD HH:mm:ss') }}</div>
</div> </div>
<div><img :src="props.itemInfo?.ownedUserIdInfo?.avatar" alt="" srcset="" class="h-[40px] w-[40px] rd-[50%]" /></div> <div><img :src="props.itemInfo?.ownedUserIdInfo?.avatar" alt="" srcset="" class="h-[40px] w-[40px] rd-[50%]" /></div>
</div> </div>
<div class="mt-[24px] flex items-center justify-between"> <div class="mt-[14px] flex items-center justify-between">
<div class="flex items-center justify-between text-[14px] text-[#666666] font-normal"> <div class="flex items-center justify-between text-[14px] text-[#666666] font-normal">
<div class="mr-[9px] flex items-center"> <div class="mr-[9px] flex items-center">
<img src="~/assets/images/look.png" alt="" srcset="" class="mr-[2px] h-[17px]" /> <img src="~/assets/images/look.png" alt="" srcset="" class="mr-[2px] h-[17px]" />
@ -35,6 +40,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import dayjs from 'dayjs'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { pageRes } from '~/api/upnew/types' import type { pageRes } from '~/api/upnew/types'
const props = defineProps({ const props = defineProps({

View File

@ -1,16 +1,16 @@
<template> <template>
<div class="mt-30px bg-[#14213d] px-[40px] pb-[20px] pt-[50px] text-white lg:px-[80px] sm:px-[60px]"> <div class="mt-[30px] bg-[#14213d] px-[40px] pb-[20px] pt-[50px] text-white lg:px-[80px] sm:px-[60px]">
<!-- 主内容区 --> <!-- 主内容区 -->
<div class="mb-[40px] flex flex-col items-start justify-between gap-[30px] lg:flex-row"> <div class="mb-[40px] flex flex-col items-start justify-between gap-[30px] lg:flex-row">
<!-- 左侧 Logo --> <!-- 左侧 Logo -->
<div class="mx-auto w-[200px] shrink-0 lg:mx0"> <div class="mx-auto w-[200px] shrink-0 lg:mx-0">
<img src="~/assets/images/logo5.png" class="h-auto w-full" /> <img src="~/assets/images/logo5.png" class="h-auto w-full" />
</div> </div>
<!-- 中间部分 --> <!-- 中间部分 -->
<div class="grid grid-cols-2 mx-[80px] flex-1 gap-[10px] lg:grid-cols-3"> <div class="grid grid-cols-2 mx-[80px] flex-1 gap-[10px] lg:grid-cols-3">
<div v-for="(col, index) in bannerList?.slice(0, 3)" :key="index"> <div v-for="(col, index) in bannerList?.slice(0, 3)" :key="index">
<h3 v-if="handle(col)" class="ma-0px mb-[20px] pa-0px text-[16px]">{{ handle(col) }}</h3> <h3 v-if="handle(col)" class="ma-[0px] mb-[20px] pa-[0px] text-[16px]">{{ handle(col) }}</h3>
<ul> <ul>
<li <li
v-for="(item, i) in handle2(col)" v-for="(item, i) in handle2(col)"
@ -44,6 +44,8 @@
<div class="border-t border-white/20 pt-[20px] text-center text-[14px] text-white/70"> <div class="border-t border-white/20 pt-[20px] text-center text-[14px] text-white/70">
Copyright 2007-2025 图夕夕网络科技(成都)有限公司 Copyright 2007-2025 图夕夕网络科技(成都)有限公司
<a href="http://beian.miit.gov.cn/" target="_blank" class="text-white/90 hover:text-blue-400!"> 蜀ICP备2025141494号-1</a> <a href="http://beian.miit.gov.cn/" target="_blank" class="text-white/90 hover:text-blue-400!"> 蜀ICP备2025141494号-1</a>
<img src="~/assets/images/x.png" class="w-[20px] h-[20px] relative top-[2px]" />
<a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=51010702043645" rel="noreferrer" target="_blank">川公网安备51010702043645号</a >
</div> </div>
<el-image-viewer v-if="showViewer" :url-list="previewImgList" :url-index="0" @close="showViewer = false"></el-image-viewer> <el-image-viewer v-if="showViewer" :url-list="previewImgList" :url-index="0" @close="showViewer = false"></el-image-viewer>

View File

@ -62,12 +62,12 @@
// 用户中心 // 用户中心
const handleUserCenter = () => { const handleUserCenter = () => {
navigateTo('/personal-Center/info') navigateTo('/personal-center/info')
} }
// 消息中心 // 消息中心
const handleMessageCenter = () => { const handleMessageCenter = () => {
navigateTo('/personal-Center/message-center') navigateTo('/personal-center/message-center')
} }
</script> </script>
<style scoped> <style scoped>

View File

@ -3,7 +3,9 @@
<div class="relative ma-auto flex items-center py-[20px] w-[1500px]!"> <div class="relative ma-auto flex items-center py-[20px] w-[1500px]!">
<img src="~/assets/images/logo5.png" alt="图夕夕" srcset="" class="h-[51px] w-[182px] cursor-pointer" @click="navigateTo('/')" /> <img src="~/assets/images/logo5.png" alt="图夕夕" srcset="" class="h-[51px] w-[182px] cursor-pointer" @click="navigateTo('/')" />
<div class="ml-[60px] flex items-center"> <div class="ml-[60px] flex items-center">
<span v-for="item in tdkList" :key="item.id" class="nav" :class="props.active === item.remark ? 'active' : ''" @click="handleClick(item.path)">{{ item.remark }}</span> <span v-for="item in tdkList" :key="item.id" class="nav" :class="props.active === item.remark ? 'active' : ''" @click="handleClick(item.path)">{{
item.remark
}}</span>
</div> </div>
<div class="relative ml-[30px]"> <div class="relative ml-[30px]">
<el-input <el-input
@ -38,11 +40,11 @@
<div class="absolute right-[10px] flex items-center"> <div class="absolute right-[10px] flex items-center">
<div class="h-[36px] w-[36px] border-rd-[50%] bg-[#F5F5F5] text-center line-height-[44px]"> <div class="h-[36px] w-[36px] border-rd-[50%] bg-[#F5F5F5] text-center line-height-[44px]">
<img v-if="!isLogin" src="~/assets/images/user.png" alt="" srcset="" class="h-[19px] w-[17px] relative top-[0px] left-[0px]" /> <img v-if="!isLogin" src="~/assets/images/user.png" alt="" srcset="" class="h-[19px] w-[17px] relative top-[0px] left-[0px]" />
<img v-else :src="userStore.userInfoRes.avatar" alt="" srcset="" class="h-[19px] w-[17px] rd-[50%]" /> <img v-else :src="userStore.userInfoRes.avatar" alt="" srcset="" class="h-full w-full rd-[50%]" />
</div> </div>
<span v-if="!isLogin" class="ml-[14px] cursor-pointer text-[14px] text-[#1A65FF] font-normal" @click="handleLogin">立即登录</span> <span v-if="!isLogin" class="ml-[14px] cursor-pointer text-[14px] text-[#1A65FF] font-normal" @click="handleLogin">立即登录</span>
<el-dropdown v-else placement="top-start" @command="handleCommand"> <el-dropdown v-else placement="top-start" @command="handleCommand">
<span class="ml-[14px] cursor-pointer text-[14px] text-[#1A65FF] font-normal">{{ userStore.userInfoRes.nickname || '立即登录' }}</span> <span class="ml-[10px] cursor-pointer text-[14px] text-[#1A65FF] font-normal">{{ userStore.userInfoRes.nickname || '立即登录' }}</span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="个人中心" <el-dropdown-item command="个人中心"
@ -166,7 +168,7 @@
userStore.logout() userStore.logout()
userStore.$reset() userStore.$reset()
} else if (command === '个人中心') { } else if (command === '个人中心') {
navigateTo('/personal-Center/info') navigateTo('/personal-center/info')
} }
} }

View File

@ -11,7 +11,7 @@
<!-- <div class="vip-card-subtitle">中小微企业</div> --> <!-- <div class="vip-card-subtitle">中小微企业</div> -->
</div> </div>
<div class="vip-card-price"> <div class="vip-card-price">
<span class="price">{{ accDiv(item.payPrice || 0, 100) }}</span> <span class="price">{{ item.payPrice }}</span>
<span class="per">/1</span> <span class="per">/1</span>
</div> </div>
<ul class="vip-card-features"> <ul class="vip-card-features">
@ -36,7 +36,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, onMounted } from 'vue' import { ref, watch, onMounted } from 'vue'
import { listVip, submitPayOrder, getPayStatus } from '~/api/pay/index' import { listVip, submitPayOrder, getPayStatus } from '~/api/pay/index'
import { accDiv } from '~/utils/utils' // import { accDiv } from '~/utils/utils'
import { Close } from '@element-plus/icons-vue' import { Close } from '@element-plus/icons-vue'
import type { AppPayWalletPackageRespVO } from '~/api/pay/types' import type { AppPayWalletPackageRespVO } from '~/api/pay/types'
// @ts-ignore // @ts-ignore
@ -153,8 +153,10 @@
.vip-cards { .vip-cards {
display: flex; display: flex;
gap: 32px; gap: 32px;
justify-content: center; /* justify-content: center; */
margin: 24px 0; margin: 24px 0;
overflow-x: auto;
padding: 10px;
} }
.vip-card { .vip-card {
background: #fff; background: #fff;

View File

@ -323,7 +323,7 @@
// 判断是否是图片 // 判断是否是图片
const handelFileType = (fileName: string) => { const handelFileType = (fileName: string) => {
const ext = fileName.split('.').pop()?.toLowerCase() || '' const ext = fileName?.split('.').pop()?.toLowerCase() || ''
return ['png', 'jpg', 'jpeg'].includes(ext) return ['png', 'jpg', 'jpeg'].includes(ext)
} }
</script> </script>

View File

@ -1,8 +1,9 @@
<template> <template>
<div class="relative mt-[34px] w-[100%]"> <div class="relative mt-[34px] w-[100%]">
<KlTabBar v-model="query.source" :data="tabBar" /> <KlTabBar v-model="query.source" :data="tabBar" />
<div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal" <div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal">
><span class="color-[#1A65FF]">{{ result?.total }}</span <el-button type="warning" class="mr-4px" @click="handleUpload">上传工具</el-button>
<span class="color-[#1A65FF]">{{ result?.total }}</span
>个筛选结果</div >个筛选结果</div
> >
<div class="content mt-[10px]"> <div class="content mt-[10px]">
@ -22,11 +23,12 @@
import { ref } from 'vue' import { ref } from 'vue'
import type { pageRes, pageReq } from '~/api/upnew/types' import type { pageRes, pageReq } from '~/api/upnew/types'
import emptyImg from '~/assets/images/empty.png' import emptyImg from '~/assets/images/empty.png'
import useUserStore from '~/stores/user'
const query = defineModel<pageReq>('modelValue', { const query = defineModel<pageReq>('modelValue', {
required: true, required: true,
}) })
const result = defineModel<pageRes| null>('result', { const result = defineModel<pageRes | null>('result', {
required: true, required: true,
}) })
@ -44,6 +46,15 @@
value: 2, value: 2,
}, },
]) ])
const handleUpload = () => {
// 先判断登录
const store = useUserStore()
if (!store.token) {
return ElMessage.error('请先登录')
}
navigateTo('/upnew?drawType=3')
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -1,10 +1,11 @@
<template> <template>
<div class="relative mt-[34px] w-[100%]"> <div class="relative mt-[34px] w-[100%]">
<KlTabBar v-model="query.source" :data="tabBar" /> <KlTabBar v-model="query.source" :data="tabBar" />
<div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal" <div class="absolute right-[0px] top-[0px] text-[16px] text-[#999999] font-normal">
><span class="color-[#1A65FF]">{{ result?.total }}</span <el-button type="warning" class="mr-4px" @click="handleUpload">上传工具</el-button>
>个筛选结果</div <span class="color-[#1A65FF]">{{ result?.total }}</span>
> 个筛选结果
</div>
<div class="content mt-[10px]"> <div class="content mt-[10px]">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col v-for="(item, index) in result?.list" :key="index" :span="6"> <el-col v-for="(item, index) in result?.list" :key="index" :span="6">
@ -22,6 +23,7 @@
import { ref } from 'vue' import { ref } from 'vue'
import type { pageRes, pageReq } from '~/api/upnew/types' import type { pageRes, pageReq } from '~/api/upnew/types'
import emptyImg from '~/assets/images/empty.png' import emptyImg from '~/assets/images/empty.png'
import useUserStore from '~/stores/user'
const query = defineModel<pageReq>('modelValue', { const query = defineModel<pageReq>('modelValue', {
required: true, required: true,
@ -34,7 +36,7 @@
const tabBar = ref([ const tabBar = ref([
{ {
label: '文本推荐', label: '文本推荐',
value: -1 value: -1,
}, },
{ {
label: '原创文本', label: '原创文本',
@ -45,6 +47,15 @@
value: 2, value: 2,
}, },
]) ])
const handleUpload = () => {
// 先判断登录
const store = useUserStore()
if (!store.token) {
return ElMessage.error('请先登录')
}
navigateTo('/upnew?drawType=2')
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -0,0 +1,77 @@
<template>
<div class="box-border w-[100%] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[20px] py-[26px]">
<div class="mb-[10px] flex items-start">
<div class="flex-shrink-0 text-[15px] text-[#333333] font-normal">软件分类</div>
<div class="ml-[30px] mt-[-6px] flex flex-wrap">
<div
v-for="(item, index) in projectTypeList"
:key="index"
class="mb-[8px] mr-[26px] cursor-pointer rounded-[15px] px-[15px] py-[6px] text-[14px] text-[#666666] font-normal"
:class="item.id === query ? '!bg-[#ebeefe] !text-[#1A65FF]' : ''"
@click="handleClick(item)"
>{{ item.name }}</div
>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { parent } from '~/api/upnew/index'
import type { pageReq } from '~/api/upnew/types'
import { getDictTree } from '~/api/home/index'
import { ArrowRight } from '@element-plus/icons-vue'
const props = defineProps({
type: {
type: Number,
default: 1,
},
id: {
type: String,
default: '',
},
groundId: {
type: String,
default: '',
},
})
const query = defineModel<string | undefined>('modelValue', {
required: true,
})
// 服务端渲染兼容方案:顺序执行异步操作
// 1. 先获取面包屑数据已在上面通过useAsyncData获取
// 2. 顺序获取分类下拉框数据
// 创建一个函数来获取分类数据,确保服务端渲染时能获取到数据
const getProjectTypeList = async () => {
try {
// 获取分类数据
const res = await parent({
type: 3,
parentId: 0,
})
const all = [{ id: '-1', name: '全部' }]
return [...all, ...res.data]
} catch (error) {
return []
}
}
// 使用useAsyncData获取分类列表确保服务端渲染兼容性
const { data: projectTypeList } = await useAsyncData(
`projectType-draw-toolbox-${props.type}-${query.value}}`,
getProjectTypeList,
{ server: true } // 确保在服务端执行
)
const handleClick = (row: any) => {
query.value = row.id
}
const handleClickBread = (row: any, index: number) => {
query.value = row.id
}
</script>

View File

@ -0,0 +1,62 @@
<template>
<el-dialog v-model="dialogVisible" title="提现申请" width="600" :before-close="handleClose">
<el-form :model="form" label-width="80px">
<el-form-item label="收款账户" prop="amount">
<el-input v-model="form.amount" placeholder="微信手机账号" />
<div class="text-12px color-#A8ABB2">*仅支持微信收款用户需在微信[收付款>向手机号转账>手机号收款设置]开启收款开关*</div>
</el-form-item>
<el-form-item label="提现类型" prop="amount">
<el-radio-group v-model="form.amount">
<el-radio :label="1">收益提现</el-radio>
<el-radio :label="2">全部提现</el-radio>
</el-radio-group>
<div class="text-12px color-#A8ABB2">*收益提现将收益金币提现全部提现可将充值金币提现*</div>
</el-form-item>
<el-form-item label="提现金额" prop="amount">
<div class="flex items-center">
<el-input-number v-model="form.amount" :controls="false" :min="0" placeholder="请输入提现金额" class="w-150px!" />
<div class="ml-10px">[可提现金币数<span class="text-red">1200</span>=<span class="text-red">120</span> ]</div>
</div>
<div class="text-12px color-#A8ABB2">*提现金币比例10金币=1元最低提现额度100元*</div>
</el-form-item>
</el-form>
<div class="text-12px color-red">
提示:收益金币提现正常收取平台手续费{{ walletConfig?.withdrawRateOfEarn }}%如需将充值金币提现选择全部提现选项因涉及充值赠送金额将收取{{ walletConfig?.withdrawRateOfRecharge }}%高额手续费如果恶意套利提现将提现审核不通过!
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false"> 立即申请 </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { getWalletConfig } from '~/api/personal-center/index'
const dialogVisible = defineModel('modelValue', {
default: false,
})
const form = reactive({
amount: 0,
})
const handleClose = (done: () => void) => {
done()
}
const walletConfig = ref<{
rechargeRate: number
commissionRate: number
withdrawRateOfRecharge: number
withdrawRateOfEarn: number
}>()
onMounted(() => {
getWalletConfig().then((res) => {
walletConfig.value = res.data
})
})
</script>
<style lang="scss" scoped></style>

99
components/wx.vue Normal file
View File

@ -0,0 +1,99 @@
<!-- 二维码弹窗 -->
<template>
<div>
<el-dialog title="微信登录" v-model="visible" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" @before-close="close">
<qrcode-vue :value="qrcode" :size="300" :margin="2" colorDark="#2c3e50" colorLight="#f8f9fa" errorCorrectionLevel="H" />
<!-- 扫码状态 -->
<div class="text-center">
<span>{{ checkLoginStatus }}</span>
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import useUserStore from '~/stores/user'
import { getLoginQrcode, checkScanStatus } from '~/api/personal-center/index'
import QrcodeVue from 'qrcode.vue'
const store = useUserStore()
const visible = defineModel('visible', {
default: false,
})
const checkLoginStatus = computed(() => {
const type = {
EXPIRED: '已过期',
CONFIRMED: '已确认',
SCANNED: '已扫码',
WAITING: '等待扫码',
SUCCESS: '登录成功',
}
if (checkLoginInfo.value) {
return type[checkLoginInfo.value.status as keyof typeof type]
}
return '微信扫码登录'
})
const qrcode = ref('')
const sceneStr = ref('')
const timer = ref<any>()
const getQrcode = async () => {
// 获取二维码
const res = await getLoginQrcode()
if (res.code === 0) {
const jsonurl = res.data.qrCodeUrl
const qrCodeUrl = jsonurl ? JSON.parse(jsonurl) : ''
if (qrCodeUrl?.qrCodeUrl) {
qrcode.value = qrCodeUrl.qrCodeUrl
sceneStr.value = res.data.sceneStr
// 轮询检查扫码状态
getCheckScanStatus()
}
}
}
const checkLoginInfo = ref<{ status: string; openId: string | null; message: string }>()
const getCheckScanStatus = async () => {
// 轮询检查扫码状态
timer.value = setInterval(async () => {
const response = await checkScanStatus({ sceneStr: sceneStr.value })
if (response.code === 0) {
checkLoginInfo.value = response.data
if (checkLoginInfo.value.status === 'SCANNED') {
// 登录
await store.getTokenV2({ openId: checkLoginInfo.value.openId as string, sceneStr: sceneStr.value })
// 扫码成功
visible.value = false
clearInterval(timer.value)
} else if (checkLoginInfo.value.status === 'EXPIRED') {
// 二维码过期
clearInterval(timer.value)
// 重新获取二维码
getQrcode()
}
}
}, 5000)
}
const close = () => {
visible.value = false
qrcode.value = ''
}
onMounted(() => {
// 获取二维码
getQrcode()
})
// 关闭定时器
onUnmounted(() => {
clearInterval(timer.value)
})
</script>
<style lang="scss" scoped>
:deep(.el-dialog__body) {
text-align: center !important;
}
</style>

View File

@ -1,77 +1,56 @@
import { isArray } from "~/utils/utils"; import { isArray } from '~/utils/utils'
import useUserStore from '~/stores/user'
// import refreshToken from "~/utils/RefreshToken"; // import refreshToken from "~/utils/RefreshToken";
type FetchType = typeof $fetch; type FetchType = typeof $fetch
export type FetchOptions = Parameters<FetchType>[1]; export type FetchOptions = Parameters<FetchType>[1]
const useClientRequest = async <T = unknown>( const useClientRequest = async <T = unknown>(url: string, opts?: FetchOptions) => {
url: string, const token = useCookie<string | undefined>('token')
opts?: FetchOptions const runtimeConfig = useRuntimeConfig()
) => { const userStore = useUserStore()
const token = useCookie<string | undefined>("token");
const runtimeConfig = useRuntimeConfig();
const defaultOptions: FetchOptions = { const defaultOptions: FetchOptions = {
baseURL: runtimeConfig.public.apiBase, baseURL: runtimeConfig.public.apiBase,
onRequest({ options }) { onRequest({ options }) {
options.headers = options.headers || 'application/json'; options.headers = options.headers || 'application/json'
if (token.value) { if (token.value || userStore.token) {
options.headers.set("Authorization", `Bearer ${token.value}`); options.headers.set('Authorization', `Bearer ${token.value || userStore.token}`)
} }
}, },
onResponse({ response }) { onResponse({ response }) {
if (+response.status === 200 && +response._data.code !== 0) { if (+response.status === 200 && +response._data.code !== 0) {
ElMessage.error(response._data.msg); ElMessage.error(response._data.msg)
} }
}, },
onResponseError({ response }) { onResponseError({ response }) {
ElMessage.error( ElMessage.error(isArray(response._data.data.msg) ? response._data.data.msg[0] : response._data.data.msg)
isArray(response._data.data.msg)
? response._data.data.msg[0]
: response._data.data.msg
);
}, },
};
// 明确转换返回类型
const response = await $fetch(url, { ...defaultOptions, ...opts });
return response as unknown as T;
};
// GET请求
export const get = <T = unknown>(
endpoint: string,
config?: Omit<FetchOptions, 'method'>
): Promise<T> => {
return useClientRequest<T>(endpoint, { ...config, method: 'GET' })
} }
// POST请求 // 明确转换返回类型
export const post = <T = unknown>( const response = await $fetch(url, { ...defaultOptions, ...opts })
endpoint: string, return response as unknown as T
body?: any, }
config?: Omit<FetchOptions, 'method' | 'body'>
): Promise<T> => {
return useClientRequest<T>(endpoint, { ...config, method: 'POST', body })
}
// GET请求
// DELETE请求 export const get = <T = unknown>(endpoint: string, config?: Omit<FetchOptions, 'method'>): Promise<T> => {
export const del = <T = unknown>( return useClientRequest<T>(endpoint, { ...config, method: 'GET' })
endpoint: string, }
config?: Omit<FetchOptions, 'method'>
): Promise<T> => {
return useClientRequest<T>(endpoint, { ...config, method: 'DELETE' })
}
// PUT请求 // POST请求
export const put = <T = unknown>( export const post = <T = unknown>(endpoint: string, body?: any, config?: Omit<FetchOptions, 'method' | 'body'>): Promise<T> => {
endpoint: string, return useClientRequest<T>(endpoint, { ...config, method: 'POST', body })
body?: any, }
config?: Omit<FetchOptions, 'method' | 'body'>
): Promise<T> => { // DELETE请求
console.log({ ...config, method: 'PUT', body }); export const del = <T = unknown>(endpoint: string, config?: Omit<FetchOptions, 'method'>): Promise<T> => {
return useClientRequest<T>(endpoint, { ...config, method: 'DELETE' })
return useClientRequest<T>(endpoint, { ...config, method: 'PUT', body }) }
}
// PUT请求
export const put = <T = unknown>(endpoint: string, body?: any, config?: Omit<FetchOptions, 'method' | 'body'>): Promise<T> => {
console.log({ ...config, method: 'PUT', body })
return useClientRequest<T>(endpoint, { ...config, method: 'PUT', body })
}

View File

@ -1,17 +1,20 @@
import { useFetch } from '#app' import { useFetch } from '#app'
import type { UseFetchOptions } from '#app' import type { UseFetchOptions } from '#app'
import { isArray } from '~/utils/utils' import { isArray } from '~/utils/utils'
import useUserStore from '~/stores/user'
const useServerRequest = async <T>(url: string, opts?: UseFetchOptions<T, unknown>) => { const useServerRequest = async <T>(url: string, opts?: UseFetchOptions<T, unknown>) => {
const token = useToken() const token = useToken()
const runtimeConfig = useRuntimeConfig() const runtimeConfig = useRuntimeConfig()
const userStore = useUserStore()
const defaultOptions: UseFetchOptions<unknown> = { const defaultOptions: UseFetchOptions<unknown> = {
baseURL: runtimeConfig.public.apiBase, baseURL: runtimeConfig.public.apiBase,
onRequest({ options }) { onRequest({ options }) {
options.headers = options.headers || {} options.headers = options.headers || {}
if (token.value) {
options.headers.set('Authorization', `Bearer ${token.value}`) if (token.value || userStore.token) {
options.headers.set('Authorization', `Bearer ${token.value || userStore.token}`)
} }
}, },
onResponse({ response }) { onResponse({ response }) {

81
composables/useMessage.ts Normal file
View File

@ -0,0 +1,81 @@
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
export const useMessage = () => {
return {
// 消息提示
info(content: string) {
ElMessage.info(content)
},
// 错误消息
error(content: string) {
ElMessage.error(content)
},
// 成功消息
success(content: string) {
ElMessage.success(content)
},
// 警告消息
warning(content: string) {
ElMessage.warning(content)
},
// 弹出提示
alert(content: string, title: string) {
ElMessageBox.alert(content, title)
},
// 错误提示
alertError(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'error' })
},
// 成功提示
alertSuccess(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'success' })
},
// 警告提示
alertWarning(content: string, title: string) {
ElMessageBox.alert(content, title, { type: 'warning' })
},
// 通知提示
notify(content: string) {
ElNotification.info(content)
},
// 错误通知
notifyError(content: string) {
ElNotification.error(content)
},
// 成功通知
notifySuccess(content: string) {
ElNotification.success(content)
},
// 警告通知
notifyWarning(content: string) {
ElNotification.warning(content)
},
// 确认窗体
confirm(content: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options
})
},
// 删除窗体
delConfirm(content?: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options
})
},
// 导出窗体
exportConfirm(content?: string, title?: string, options?: any) {
return ElMessageBox.confirm(content, title, {
type: 'warning',
...options
})
},
// 提交内容
prompt(content: string, title: string, options?: any) {
return ElMessageBox.prompt(content, title, {
type: 'warning',
...options
})
}
}
}

20
layouts/success.vue Normal file
View File

@ -0,0 +1,20 @@
<template>
<div class="layout-wrap">
<div class="flex flex-1 flex-col">
<slot></slot>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.layout-wrap {
flex: 1;
display: flex;
flex-direction: column;
background-color: #fbfcff;
width: 100%;
margin: auto;
}
</style>

View File

@ -5,7 +5,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
// 获取当前路由 // 获取当前路由
const currentPath = to.path; const currentPath = to.path;
// 根据当前路由获取对应的TDK数据 // 根据当前路由获取对应的TDK数据
const currentTdk = tdkData.find((item) => item.path === currentPath) const currentTdk = tdkData?.find((item) => item.path === currentPath)
if (currentTdk) { if (currentTdk) {
useHead({ useHead({

View File

@ -1,5 +1,6 @@
{ {
"name": "nuxt-app", "name": "nuxt-app",
"version": "1.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@ -0,0 +1,139 @@
<template>
<div class="auth-success-container">
<!-- 顶部成功图标 -->
<div class="success-icon">
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="40" cy="40" r="40" fill="#4CD964" />
<path d="M25 40L35 50L55 30" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
<!-- 标题和描述 -->
<div class="text-content">
<h1 class="title">授权成功</h1>
<p class="desc">
您已完成微信授权<br />
请返回电脑端继续操作
</p>
</div>
<!-- 倒计时提示 -->
<!-- <div class="countdown" v-if="countdown > 0">
<p>页面将在 {{ countdown }} 秒后自动关闭</p>
</div> -->
<!-- 底部按钮 -->
<!-- <div class="btn-group">
<button class="close-btn" @click="closePage">立即关闭</button>
</div> -->
</div>
</template>
<script setup lang="ts">
import { notifyAuthSuccess } from '~/api/login/index'
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
definePageMeta({
layout: 'success',
})
onMounted(() => {
notifyAuthSuccess({ code: route.query.code as string, state: route.query.state as string }).then(() => {
console.log('Notified backend of auth success')
})
})
</script>
<style scoped>
.auth-success-container {
min-height: 100vh;
box-sizing: border-box;
padding: 20px;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.success-icon {
margin-bottom: 30px;
animation: pop 0.5s ease-out;
}
@keyframes pop {
0% {
transform: scale(0.8);
opacity: 0;
}
70% {
transform: scale(1.1);
}
100% {
transform: scale(1);
opacity: 1;
}
}
.text-content {
text-align: center;
margin-bottom: 40px;
}
.title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 15px 0;
}
.desc {
font-size: 16px;
color: #666;
line-height: 1.6;
margin: 0;
}
.countdown {
margin-bottom: 50px;
color: #999;
font-size: 14px;
}
.btn-group {
width: 100%;
max-width: 300px;
}
.close-btn {
width: 100%;
height: 48px;
background-color: #07c160;
color: white;
border: none;
border-radius: 24px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
}
.close-btn:hover {
background-color: #06b355;
}
/* 适配小屏手机 */
@media (max-width: 320px) {
.title {
font-size: 22px;
}
.desc {
font-size: 15px;
}
.close-btn {
height: 44px;
font-size: 15px;
}
}
</style>

View File

@ -2,6 +2,7 @@
<div class="ml-[19px] w-[100%]"> <div class="ml-[19px] w-[100%]">
<ChannelHeader v-if="Object.keys(lunTanRes || {}).length" v-model="lunTanRes"></ChannelHeader> <ChannelHeader v-if="Object.keys(lunTanRes || {}).length" v-model="lunTanRes"></ChannelHeader>
<div <div
v-if="pageRes?.list.length"
class="mb-[13px] box-border flex flex-1 flex-col cursor-pointer gap-[12px] border border-[#EEEEEE] rounded-[8px] border-solid bg-[#FFFFFF] px-[20px] py-[16px]" class="mb-[13px] box-border flex flex-1 flex-col cursor-pointer gap-[12px] border border-[#EEEEEE] rounded-[8px] border-solid bg-[#FFFFFF] px-[20px] py-[16px]"
> >
<div <div
@ -20,7 +21,7 @@
<div class="w-[100px] flex flex-shrink-0 items-center justify-end"> <div class="w-[100px] flex flex-shrink-0 items-center justify-end">
<span class="ellipsis text-[13px] color-[#96999f]">{{ item.creatorName }}</span> <span class="ellipsis text-[13px] color-[#96999f]">{{ item.creatorName }}</span>
<!-- 删除 --> <!-- 删除 -->
<el-button v-if="false" type="danger" size="small" @click="handleDelete(item.postsId)">删除</el-button> <el-button v-if="false" type="danger" size="small" @click.stop="handleDelete(item.postsId)">删除</el-button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -13,15 +13,15 @@
</div> </div>
<div class="mt-[19px] flex items-center justify-between"> <div class="mt-[19px] flex items-center justify-between">
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/look.png" alt="" srcset="" class="mr-[4px] h-[17px]" /> <img src="~/assets/images/look.png" alt="" srcset="" class="mr-[4px] h-[14px]" />
<span class="text-[#666666]">{{ channelDetail?.likeNum || 0 }}人赞过</span> <span class="text-[#666666]">{{ channelDetail?.likeNum || 0 }}人赞过</span>
<div class="ml-[16px] flex items-center"> <div class="ml-[16px] flex items-center">
<img src="~/assets/images/add.png" alt="" class="mr-[4px] h-[23px]" /> <img src="~/assets/images/add.png" alt="" class="mr-[4px] h-[20px]" />
<span class="text-[#666666]">{{ channelDetail?.commentNum || 0 }}评论</span> <span class="text-[#666666]">{{ channelDetail?.commentNum || 0 }}评论</span>
</div> </div>
</div> </div>
<div class="ml-[16px] flex items-center"> <div class="ml-[16px] flex items-center">
<img src="~/assets/images/chat.png" alt="" srcset="" class="mr-[4px] h-[17px]" /> <img src="~/assets/images/chat.png" alt="" srcset="" class="mr-[4px] h-[14px]" />
<span class="text-[#666666]">{{ channelDetail?.browseNum || 0 }}人看过</span> <span class="text-[#666666]">{{ channelDetail?.browseNum || 0 }}人看过</span>
</div> </div>
</div> </div>
@ -104,7 +104,6 @@
const channelId = computed(() => route.params.channelId as string) const channelId = computed(() => route.params.channelId as string)
const pageNo = computed(() => Number(route.params.pageNo)) const pageNo = computed(() => Number(route.params.pageNo))
console.log(channelId.value, pageNo.value)
// const channelDetail = ref<TGetChannelPostsRes>() // const channelDetail = ref<TGetChannelPostsRes>()
// const commentList = reactive<PageResultPostsCommentRespVO>({ // const commentList = reactive<PageResultPostsCommentRespVO>({

View File

@ -1,19 +1,24 @@
<template> <template>
<SeoHead :title="detail?.title" :description="detail?.description" :keywords="detail?.labels?.toString()" /> <SeoHead :title="detail?.title" :description="detail?.description" :keywords="detail?.labels?.toString()" />
<KlNavTab /> <KlNavTab />
<div v-if="breadList && breadList.length > 1" class="mb-[-10px] mt-[20px] w-[1440px] mx-auto">
<el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">{{ item.name }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="ml-auto mr-auto mt-[20px] w-[1440px]"> <div class="ml-auto mr-auto mt-[20px] w-[1440px]">
<div class="flex items-center"> <div class="flex items-center">
<div <div
class="box-border h-[60px] w-[1019px] flex items-center justify-between border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[27px] py-[24px]" class="box-border h-[60px] w-[1019px] flex items-center justify-between border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[27px] py-[24px]"
> >
<div class="text-[20px] text-[#333333] font-normal"> {{ detail?.title }}</div> <div class="text-[16px] text-[#333333] font-normal"> {{ detail?.title }}</div>
<div class="flex items-center"> <div class="flex items-center">
<img :src="detail?.ownedUserIdInfo?.avatar" alt="" srcset="" class="h-[30px] w-[30px] rd-[50%]" /> <img :src="detail?.ownedUserIdInfo?.avatar" alt="" srcset="" class="h-[30px] w-[30px] rd-[50%]" />
<span class="ml-[12px] color-[#999999]">by {{ detail?.ownedUserIdInfo?.nickName }}</span> <span class="ml-[12px] color-[#999999]">by {{ detail?.ownedUserIdInfo?.nickName }}</span>
</div> </div>
</div> </div>
<div class="ml-[23px] flex flex-1 text-[18px] text-[#FFFFFF] font-normal"> <div class="ml-[23px] flex flex-1 text-[16px] text-[#FFFFFF] font-normal">
<div class="h-[60px] w-[160px] flex cursor-pointer items-center justify-center rounded-[8px] bg-[#1A65FF]" @click="handleDownload"> <div class="h-[60px] w-[160px] flex cursor-pointer items-center justify-center rounded-[8px] bg-[#1A65FF]" @click="handleDownload">
<img src="~/assets/images/download.png" alt="" srcset="" class="mr-[4px] h-[22px] w-[27px]" /> <img src="~/assets/images/download.png" alt="" srcset="" class="mr-[4px] h-[22px] w-[27px]" />
{{ detail?.points === 0 ? '免费下载' : '立即下载' }} {{ detail?.points === 0 ? '免费下载' : '立即下载' }}
@ -40,23 +45,27 @@
<div> <div>
<ThumBnail :data="detail?.coverImages" :type="detail?.type"></ThumBnail> <ThumBnail :data="detail?.coverImages" :type="detail?.type"></ThumBnail>
</div> </div>
<div class="mb-[20px] mt-[34px] flex items-center text-[16px] text-[#333333] font-normal"> <div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">{{ detail?.title }}描述</span></div <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">{{ detail?.title }}描述</span></div
> >
<div <div
class="box-border min-h-[90px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px] text-[14px] text-[#333333] font-normal" class="box-border min-h-[90px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px] text-[14px] text-[#333333] font-normal"
> >
{{ detail?.description }} {{ detail?.description }}
</div> </div>
<div id="section1" class="mb-[20px] mt-[34px] flex items-center text-[16px] text-[#333333] font-normal"> <div id="section1" class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">{{ detail?.title }}附件</span></div <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">{{ detail?.title }}附件</span></div
> >
<div class="box-border w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px]"> <div class="box-border w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px]">
<div class="border-b-[1px] border-b-[#eee] border-b-solid p-b-[10px]"> <div class="border-b-[1px] border-b-[#eee] border-b-solid p-b-[10px]">
{{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}中包含的文件 {{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}中包含的文件
</div> </div>
<div> <div>
<div v-for="item in detail?.files" :key="item.id" class="flex items-center justify-between border-b-[1px] border-b-[#eee] border-b-solid py-[10px]"> <div
v-for="item in detail?.otherFiles"
:key="item.id"
class="flex items-center justify-between border-b-[1px] border-b-[#eee] border-b-solid py-[10px]"
>
<!-- <img src="~/assets/images/avater.png" alt="" srcset="" class="h-30px w-30px" /> --> <!-- <img src="~/assets/images/avater.png" alt="" srcset="" class="h-30px w-30px" /> -->
<div> <div>
<!-- <span class="ml-[10px] cursor-pointer" @click="handleDownloadPreview(item)">{{ item.title }}</span> --> <!-- <span class="ml-[10px] cursor-pointer" @click="handleDownloadPreview(item)">{{ item.title }}</span> -->
@ -77,8 +86,8 @@
</div> </div>
</div> </div>
<!-- 关联项目 --> <!-- 关联项目 -->
<div class="mb-[20px] mt-[34px] flex items-center text-[16px] text-[#333333] font-normal"> <div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div
><span class="ml-[10px]">关联{{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}</span></div ><span class="ml-[10px]">关联{{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}</span></div
> >
<el-row :gutter="20"> <el-row :gutter="20">
@ -88,8 +97,8 @@
</el-row> </el-row>
<el-empty v-if="!detail?.relationDraws?.length" description="暂无数据"></el-empty> <el-empty v-if="!detail?.relationDraws?.length" description="暂无数据"></el-empty>
<!-- 关联模型 --> <!-- 关联模型 -->
<div class="mb-[20px] mt-[34px] flex items-center text-[16px] text-[#333333] font-normal"> <div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div
><span class="ml-[10px]">相关{{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}推荐</span></div ><span class="ml-[10px]">相关{{ detail?.type === 1 ? '图纸' : detail?.type === 2 ? '文本' : '模型' }}推荐</span></div
> >
<el-row :gutter="20"> <el-row :gutter="20">
@ -102,7 +111,7 @@
</div> </div>
<div class="ml-[22px]"> <div class="ml-[22px]">
<div class="box-border min-h-[269px] w-[397px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] pa-[22px]"> <div class="box-border min-h-[269px] w-[397px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] pa-[22px]">
<div class="mb-[10px]">图纸ID: {{ detail?.id }}</div> <div class="mb-[10px]">图纸ID: {{ detail?.no }}</div>
<div class="mb-[10px]">文件大小{{ detail?.filesInfo?.fileSize || 0 }} </div> <div class="mb-[10px]">文件大小{{ detail?.filesInfo?.fileSize || 0 }} </div>
<!-- <div class="mb-10px">图纸版本{{ detail.editionsName }} </div> --> <!-- <div class="mb-10px">图纸版本{{ detail.editionsName }} </div> -->
<div class="mb-[10px]">图纸格式{{ detail?.formatType?.toString() }}</div> <div class="mb-[10px]">图纸格式{{ detail?.formatType?.toString() }}</div>
@ -137,7 +146,7 @@
<div class="h-[20px]"> <div class="h-[20px]">
<img src="~/assets/images/user4.png" alt="fans" class="w-[80%] rounded-full vertical-top" /> <img src="~/assets/images/user4.png" alt="fans" class="w-[80%] rounded-full vertical-top" />
</div> </div>
<div class="relative top-[-3px] ml-[8px] text-[14px] text-[#666] font-normal">粉丝: {{ userInfo.fansCount || 0 }}</div> <div class="relative top-[-3px] ml-[8px] text-[14px] text-[#666] font-normal">发帖数: {{ userInfo.postsNum || 0 }}</div>
</div> </div>
</div> </div>
@ -154,8 +163,8 @@
<div class="mt-[20px] h-[1px] w-[336px] rounded-[1px] bg-[#EEEEEE]"></div> <div class="mt-[20px] h-[1px] w-[336px] rounded-[1px] bg-[#EEEEEE]"></div>
<div class="mt-[20px] flex items-center"> <div class="mt-[20px] flex items-center">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div> <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div>
<span class="ml-[10px] text-[16px]">最新发布</span> <span class="ml-[10px] text-[14px]">最新发布</span>
</div> </div>
<div class="mt-[10px]"> <div class="mt-[10px]">
<div <div
@ -176,11 +185,13 @@
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { ArrowRight } from '@element-plus/icons-vue'
import { downloadFile } from '~/utils/utils' import { downloadFile } from '~/utils/utils'
import { useMessage } from '~/utils/useMessage' import { useMessage } from '~/utils/useMessage'
import { Warning } from '@element-plus/icons-vue' import { Warning } from '@element-plus/icons-vue'
import SeoHead from '~/components/seo-head/index.vue' import SeoHead from '~/components/seo-head/index.vue'
import CardPicture from '~/components/kl-card-picture/index.vue' import CardPicture from '~/components/kl-card-picture/index.vue'
import { getDictTree } from '~/api/home/index'
import { getDetail, getRelationRecommend, report, getUserInfo, getMainWork, createContent, createUserProject, deleteProject } from '~/api/drawe-detail/index' import { getDetail, getRelationRecommend, report, getUserInfo, getMainWork, createContent, createUserProject, deleteProject } from '~/api/drawe-detail/index'
import KlNavTab from '~/components/kl-nav-tab/index.vue' import KlNavTab from '~/components/kl-nav-tab/index.vue'
import ThumBnail from './components/swiper.vue' import ThumBnail from './components/swiper.vue'
@ -213,6 +224,20 @@
}) })
} }
// 获取面包屑
const { data: breadList } = await useAsyncData(`breadList-detail-${route.params.id}}`, async () => {
const res = await getDictTree({ type: 1, id: detail.value?.projectType?.[0] })
const all = [
{
id: -1,
name: detail.value?.type === 1 ? '图纸库' : detail.value?.type === 3 ? '模型库' : '文本库',
isChildren: false,
},
]
const arr = [...res.data, ...all]
return arr.reverse()
})
// const init = () => { // const init = () => {
// getDetail({ id }).then((res) => { // getDetail({ id }).then((res) => {
// if (res.code === 0) { // if (res.code === 0) {
@ -336,6 +361,7 @@
comments: value, comments: value,
projectId: detail.value?.projectId, projectId: detail.value?.projectId,
drawId: detail.value?.id, drawId: detail.value?.id,
type: detail.value?.type,
}).then((res) => { }).then((res) => {
if (res.code === 0) { if (res.code === 0) {
ElMessage.success('举报成功') ElMessage.success('举报成功')
@ -355,6 +381,7 @@
: await createContent({ : await createContent({
projectId: detail.value?.projectId, projectId: detail.value?.projectId,
drawId: detail.value?.id, drawId: detail.value?.id,
type: detail.value?.type,
}) })
if (res.code === 0) { if (res.code === 0) {
ElMessage.success(`${detail.value?.favoriteId ? '取消' : '收藏'}成功`) ElMessage.success(`${detail.value?.favoriteId ? '取消' : '收藏'}成功`)

View File

@ -10,8 +10,8 @@
<div class="swiper-button-prev"></div> <div class="swiper-button-prev"></div>
</div> </div>
</div> </div>
<div class="mb-[20px] mt-[34px] flex items-center text-[16px] text-[#333333] font-normal"> <div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div> <div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div>
<span class="ml-[10px]">{{ props.type === 1 ? '图纸' : props.type === 2 ? '文本' : '模型' }}</span> <span class="ml-[10px]">{{ props.type === 1 ? '图纸' : props.type === 2 ? '文本' : '模型' }}</span>
</div> </div>
<div class="box-border h-[126px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[23px]"> <div class="box-border h-[126px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[23px]">

View File

@ -62,6 +62,7 @@
source: source.value || -1, source: source.value || -1,
type: 1, type: 1,
title: keywords.value, title: keywords.value,
recommend: source.value === -1 ? true : false,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -93,6 +94,7 @@
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -55,6 +55,7 @@
source: -1, source: -1,
type: 1, type: 1,
title: keywords.value, title: keywords.value,
recommend: true,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -79,13 +80,14 @@
} }
const { data: result, refresh: getPage } = useAsyncData( const { data: result, refresh: getPage } = useAsyncData(
`draw-page-list-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}-${query.value.title}`, `draw-page-list-drawe-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}-${query.value.title}`,
async () => { async () => {
const res = await page({ const res = await page({
...query.value, ...query.value,
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -79,7 +79,7 @@
<div class="text-[15px] color-[#999]">{{ dayjs(item.createTime).format('MM-DD') }}</div> <div class="text-[15px] color-[#999]">{{ dayjs(item.createTime).format('MM-DD') }}</div>
</div> </div>
<!-- 暂无数据 --> <!-- 暂无数据 -->
<el-empty v-if="!newDrawList.length" description="暂无数据"></el-empty> <el-empty v-if="!newDrawList?.length" description="暂无数据"></el-empty>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@
<div class="login-container flex flex-col justify-between"> <div class="login-container flex flex-col justify-between">
<div class="ma-auto mt-[25px] w-[100%] flex flex-col items-center"> <div class="ma-auto mt-[25px] w-[100%] flex flex-col items-center">
<el-image <el-image
:src="userStore.userInfoRes.avatar || 'https://tuxixi.oss-cn-chengdu.aliyuncs.com/avater.png'" :src="userStore.userInfoRes.avatar || 'https://static.tuxixi.net/1757297277142/2025/09/08/10/07/57/tuxixi.png'"
alt="" alt=""
srcset="" srcset=""
class="h-[69px] w-[69px] rd-[50%]" class="h-[69px] w-[69px] rd-[50%]"
@ -11,7 +11,7 @@
@click="handleUserInfo" @click="handleUserInfo"
/> />
<div class="mt-[10px] text-[16px] text-[#333333] font-normal flex items-center"> <div class="mt-[10px] text-[16px] text-[#333333] font-normal flex items-center">
Hi{{ userStore.userInfoRes.nickname || '欢迎访问~' }} Hi{{ userStore.userInfoRes.nickname || '欢迎访问图夕夕' }}
<img v-if="userStore.userInfoRes.vipLevel === 1" src="~/assets/svg/vip.svg" alt="" class="relative top-[1px]" /> <img v-if="userStore.userInfoRes.vipLevel === 1" src="~/assets/svg/vip.svg" alt="" class="relative top-[1px]" />
<img v-if="userStore.userInfoRes.vipLevel === 2" src="~/assets/svg/svip.svg" alt="" class="relative top-[1px]" /> <img v-if="userStore.userInfoRes.vipLevel === 2" src="~/assets/svg/svip.svg" alt="" class="relative top-[1px]" />
</div> </div>
@ -64,7 +64,7 @@
</div> </div>
<div v-if="!isLogin" class="mt-[30px] flex justify-between px-[20px]"> <div v-if="!isLogin" class="mt-[30px] flex justify-between px-[20px]">
<img src="~/assets/images/qq-v2.png" alt="QQ登录" class="social-icon" @click="handleLoginQQ" /> <img src="~/assets/images/qq-v2.png" alt="QQ登录" class="social-icon" @click="handleLoginQQ" />
<img src="~/assets/images/weixin-v2.png" alt="微信登录" class="social-icon" @click="handleLoginWechat" /> <img src="~/assets/images/weixin-v2.png" alt="微信登录" class="social-icon" @click="handleLoginWechatV2" />
<img src="~/assets/images/email-v2.png" alt="邮箱登录" class="social-icon" @click="handleLoginEmail" /> <img src="~/assets/images/email-v2.png" alt="邮箱登录" class="social-icon" @click="handleLoginEmail" />
<img src="~/assets/images/phone-v2.png" alt="手机登录" class="social-icon" @click="handleLoginPhone" /> <img src="~/assets/images/phone-v2.png" alt="手机登录" class="social-icon" @click="handleLoginPhone" />
</div> </div>
@ -73,6 +73,9 @@
<img src="~/assets/images/sign.png" alt="签到奖励" class="bonus-image" /> <img src="~/assets/images/sign.png" alt="签到奖励" class="bonus-image" />
</div> </div>
</div> </div>
<!-- wx二维码弹窗 -->
<wx v-model:visible="visible" v-if="visible" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -90,6 +93,12 @@
return !!userStore.token return !!userStore.token
}) })
// 打开微信二维码
const visible = ref<boolean>(false)
const handleLoginWechatV2 = () => {
visible.value = true
}
// 获取用户统计信息 // 获取用户统计信息
const userStaticInfo = ref<UserStatisticsCountRespVO>() const userStaticInfo = ref<UserStatisticsCountRespVO>()
const fetchUserStatistics = async () => { const fetchUserStatistics = async () => {

View File

@ -2,27 +2,19 @@
<template> <template>
<div class="main-content"> <div class="main-content">
<div class="flex"> <div class="flex">
<div class="h-424px w-957px"> <div class="h-[424px] w-[957px]">
<el-carousel height="424px" indicator-position="none"> <el-carousel height="424px" indicator-position="none">
<el-carousel-item v-for="(item, index) in bannerList" :key="index"> <el-carousel-item v-for="(item, index) in bannerList" :key="index">
<el-image <el-image :src="item.content" class="w-[100%]" :class="{ 'cursor-pointer': item.url }" fit="cover" @click="handleClick(item.url)" />
:src="item.content"
class="w-100%"
:class="{ 'cursor-pointer': item.url }"
fit="cover"
@click="handleClick(item.url)"
/>
</el-carousel-item> </el-carousel-item>
</el-carousel> </el-carousel>
</div> </div>
<LoginForm /> <LoginForm />
</div> </div>
<div <div class="box-border h-[56px] w-[1219px] flex items-center border border-[#EEEEEE] border-solid border-t-none bg-[#FFFFFF] pl-[10px] line-height-[46px]">
class="box-border h-56px w-1219px flex items-center border border-[#EEEEEE] border-solid border-t-none bg-[#FFFFFF] pl-10px line-height-46px" <img src="~/assets/images/voice.png" alt="" srcset="" class="mr-[10px] h-[15px] w-[16px]" />
>
<img src="~/assets/images/voice.png" alt="" srcset="" class="mr-10px h-15px w-16px" />
<Vue3Marquee :duration="10" direction="normal" pause-on-hover> <Vue3Marquee :duration="10" direction="normal" pause-on-hover>
· 经典来袭SolidWorks装配经典案例之气动发动机 <template v-for="(item, index) in noticeList" :key="index"> {{ item }} </template>
</Vue3Marquee> </Vue3Marquee>
</div> </div>
</div> </div>
@ -33,7 +25,7 @@
import LoginForm from './LoginForm.vue' import LoginForm from './LoginForm.vue'
import { Vue3Marquee } from 'vue3-marquee' import { Vue3Marquee } from 'vue3-marquee'
import { getSettingPage } from '~/api/home/index' import { getSettingPage, getNoticeList } from '~/api/home/index'
const pageReq = reactive({ const pageReq = reactive({
type: 1, type: 1,
@ -50,6 +42,8 @@
navigateTo(url) navigateTo(url)
} }
} }
const { data: noticeList } = await getNoticeList()
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -155,7 +155,7 @@
const all = [{ id: '0', name: '全部分类', children: [] }] const all = [{ id: '0', name: '全部分类', children: [] }]
if (Array.isArray(res.data) && res.data?.length > 0) { if (Array.isArray(res.data) && res.data?.length > 0) {
const total = [...res.data, ...all] const total = [...res.data, ...all]
// query.projectTypeDay = total[0]?.id || '' query.projectTypeDay = total[0]?.id || ''
// query.projectType = total[0]!.children?.[0]?.id || '' // query.projectType = total[0]!.children?.[0]?.id || ''
return total return total
} }
@ -206,10 +206,10 @@
// } // }
const handleHover = (item: ProjectDictNodeVO) => { const handleHover = (item: ProjectDictNodeVO) => {
query.projectTypeDay = item.id || ''
if (item.name === '全部分类') return if (item.name === '全部分类') return
query.projectTypeDay = item.id || ''
// projectTypeListChildren.value = item.children || [] // projectTypeListChildren.value = item.children || []
query.projectType = item.children?.[0].id || '' // query.projectType = item.id || ''
// 热门数据 // 热门数据
getHotTop() getHotTop()
} }

View File

@ -44,8 +44,6 @@
const sideMenu = ref() const sideMenu = ref()
const menuItemRefs = ref<HTMLElement[]>([]) const menuItemRefs = ref<HTMLElement[]>([])
// const menuItems = ref<ProjectDictNodeVO[]>([]);
// 等待数据加载完成再进行渲染 :courseData 对data进行别名赋值 // 等待数据加载完成再进行渲染 :courseData 对data进行别名赋值
const { const {
data: menuItems, data: menuItems,
@ -64,9 +62,6 @@
}) })
const showSubMenu = (index: number) => { const showSubMenu = (index: number) => {
// if (menuItems.value.length === index + 1) {
// return
// }
activeIndex.value = index activeIndex.value = index
const dom = menuItemRefs.value[index].getBoundingClientRect() const dom = menuItemRefs.value[index].getBoundingClientRect()
console.log(dom) console.log(dom)
@ -78,21 +73,6 @@
} }
const handleSubmenuClick = (primary: ProjectDictNodeVO) => { const handleSubmenuClick = (primary: ProjectDictNodeVO) => {
// const normal = { id: "0", name: "图纸库", isChildren: false };
// const level = [primary, secondary, tertiary]
// .filter(Boolean)
// .map((item) => ({
// id: item?.id,
// name: item?.name,
// isChildren: item?.children?.length ? false : true,
// }));
// if (primary?.id === "0") {
// level[0].name = "图纸库";
// } else {
// level.unshift(normal);
// }
// navigateTo(`/drawe?level=${JSON.stringify(level)}`)
navigateTo(`/drawe/${primary.id}/1/12/-1`) navigateTo(`/drawe/${primary.id}/1/12/-1`)
} }
@ -169,7 +149,7 @@
.menu-item { .menu-item {
/* position: relative; */ /* position: relative; */
text-align: center; text-align: center;
padding: 10px 24px; padding: 9px 24px;
cursor: pointer; cursor: pointer;
/* transition: all 0.3s ease; */ /* transition: all 0.3s ease; */
color: #333; color: #333;

View File

@ -62,6 +62,7 @@
source: source.value || -1, source: source.value || -1,
type: 3, type: 3,
title: keywords.value, title: keywords.value,
recommend: source.value === -1 ? true: false,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -93,6 +94,7 @@
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -52,6 +52,7 @@
editions: '-1', editions: '-1',
source: -1, source: -1,
type: 3, type: 3,
recommend: true,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -64,13 +65,14 @@
} }
const { data: result } = useAsyncData( const { data: result } = useAsyncData(
`draw-page-list-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}`, `draw-page-list-model-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}`,
async () => { async () => {
const res = await page({ const res = await page({
...query.value, ...query.value,
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -4,9 +4,9 @@
<div <div
class="left mt-[25px] box-border h-[370px] w-[260px] border border-[#EEEEEE] rounded-[4px] border-solid bg-[#FFFFFF] text-[15px] text-[#333333] font-medium" class="left mt-[25px] box-border h-[370px] w-[260px] border border-[#EEEEEE] rounded-[4px] border-solid bg-[#FFFFFF] text-[15px] text-[#333333] font-medium"
> >
<nuxt-link to="/personal-Center/info" class="flex items-center justify-between py-[14px]"> <nuxt-link to="/personal-center/info" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="route.path.startsWith('/personal-Center/info')" src="~/assets/images/user3.png" alt="" srcset="" class="h-[20px]" /> <img v-if="route.path.startsWith('/personal-center/info')" src="~/assets/images/user3.png" alt="" srcset="" class="h-[20px]" />
<img v-else src="~/assets/images/个人.png" alt="" srcset="" class="h-[20px]" /> <img v-else src="~/assets/images/个人.png" alt="" srcset="" class="h-[20px]" />
<span class="ml-[10px]">个人中心</span> <span class="ml-[10px]">个人中心</span>
</div> </div>
@ -15,9 +15,9 @@
</div> </div>
</nuxt-link> </nuxt-link>
<nuxt-link to="/personal-Center/personal-profile" class="flex items-center justify-between py-[14px]"> <!-- <nuxt-link to="/personal-center/personal-profile" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-Center/personal-profile')" src="~/assets/images/user_zl.png" alt="" srcset="" class="h-[16px]" /> <img v-if="!route.path.startsWith('/personal-center/personal-profile')" src="~/assets/images/user_zl.png" alt="" srcset="" class="h-[16px]" />
<img v-else src="~/assets/images/个人资料 (1).png" alt="" srcset="" class="h-[16px]" /> <img v-else src="~/assets/images/个人资料 (1).png" alt="" srcset="" class="h-[16px]" />
<span class="ml-[10px]">个人资料</span> <span class="ml-[10px]">个人资料</span>
</div> </div>
@ -25,19 +25,29 @@
<el-icon><ArrowRight /></el-icon> <el-icon><ArrowRight /></el-icon>
</div> </div>
</nuxt-link> </nuxt-link>
<nuxt-link to="/personal-Center/account-security" class="flex items-center justify-between py-[14px]"> <nuxt-link to="/personal-center/account-security" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-Center/account-security')" src="~/assets/images/account.png" alt="" srcset="" class="h-[20px]" /> <img v-if="!route.path.startsWith('/personal-center/account-security')" src="~/assets/images/account.png" alt="" srcset="" class="h-[20px]" />
<img v-else src="~/assets/images/账户安全.png" alt="" srcset="" class="h-[20px]" /> <img v-else src="~/assets/images/账户安全.png" alt="" srcset="" class="h-[20px]" />
<span class="ml-[14px]">账户与安全</span> <span class="ml-[14px]">账户与安全</span>
</div> </div>
<div class="pr-[20px]"> <div class="pr-[20px]">
<el-icon><ArrowRight /></el-icon> <el-icon><ArrowRight /></el-icon>
</div> </div>
</nuxt-link> </nuxt-link> -->
<nuxt-link to="/personal-Center/resource-center" class="flex items-center justify-between py-[14px]"> <nuxt-link to="/personal-center/account-management" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-Center/resource-center')" src="~/assets/images/ziyuan.png" alt="" srcset="" class="h-[18px]" /> <img v-if="!route.path.startsWith('/personal-center/account-management')" src="~/assets/images/account.png" alt="" srcset="" class="h-[20px]" />
<img v-else src="~/assets/images/账户安全.png" alt="" srcset="" class="h-[20px]" />
<span class="ml-[14px]">账户管理</span>
</div>
<div class="pr-[20px]">
<el-icon><ArrowRight /></el-icon>
</div>
</nuxt-link>
<nuxt-link to="/personal-center/resource-center" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-center/resource-center')" src="~/assets/images/ziyuan.png" alt="" srcset="" class="h-[18px]" />
<img v-else src="~/assets/images/资源.png" alt="" srcset="" class="h-[18px]" /> <img v-else src="~/assets/images/资源.png" alt="" srcset="" class="h-[18px]" />
<span class="ml-[12px]">资源中心</span> <span class="ml-[12px]">资源中心</span>
</div> </div>
@ -45,19 +55,19 @@
<el-icon><ArrowRight /></el-icon> <el-icon><ArrowRight /></el-icon>
</div> </div>
</nuxt-link> </nuxt-link>
<nuxt-link to="/personal-Center/trading-center" class="flex items-center justify-between py-[14px]"> <nuxt-link to="/personal-center/trading-center" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-Center/trading-center')" src="~/assets/images/pay.png" alt="" srcset="" class="h-[20px]" /> <img v-if="!route.path.startsWith('/personal-center/trading-center')" src="~/assets/images/pay.png" alt="" srcset="" class="h-[20px]" />
<img v-else src="~/assets/images/交易管理.png" alt="" srcset="" class="h-[20px]" /> <img v-else src="~/assets/images/交易管理.png" alt="" srcset="" class="h-[20px]" />
<span class="ml-[12px]">交易中心</span> <span class="ml-[12px]">交易记录</span>
</div> </div>
<div class="pr-[20px]"> <div class="pr-[20px]">
<el-icon><ArrowRight /></el-icon> <el-icon><ArrowRight /></el-icon>
</div> </div>
</nuxt-link> </nuxt-link>
<nuxt-link to="/personal-Center/message-center" class="flex items-center justify-between py-[14px]"> <nuxt-link to="/personal-center/message-center" class="flex items-center justify-between py-[14px]">
<div class="flex items-center pl-[20px]"> <div class="flex items-center pl-[20px]">
<img v-if="!route.path.startsWith('/personal-Center/message-center')" src="~/assets/images/message.png" alt="" srcset="" class="h-[18px]" /> <img v-if="!route.path.startsWith('/personal-center/message-center')" src="~/assets/images/message.png" alt="" srcset="" class="h-[18px]" />
<img v-else src="~/assets/images/消息.png" alt="" srcset="" class="h-[18px]" /> <img v-else src="~/assets/images/消息.png" alt="" srcset="" class="h-[18px]" />
<span class="ml-[14px]">消息通知</span> <span class="ml-[14px]">消息通知</span>
</div> </div>

View File

@ -0,0 +1,90 @@
<template>
<div class="box-border w-auto border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px mt-10px">
<div class="flex flex-col justify-center text-[14px] text-[#333333] font-normal">
<div class="mt-[6px] flex items-center justify-between">
<div class="flex items-center">
<el-icon size="32" color="#007AFF"><Iphone /></el-icon>
<!-- <img src="~/assets/images/qq-v2.png" alt="" srcset="" class="h-[35px] w-[34px]" /> -->
<div class="ml-[19px] w-fit flex flex-col">
<div class="color-#333 text-15px mb-4px">手机号{{ user.mobile ? '(已绑定)' : '' }}</div
><div class="color-#999">手机号可以用于登录帐号{{ user.mobile }}</div></div
>
</div>
<el-button :type="user.mobile ? 'danger' : 'primary'" class="ml-10px">{{ user.mobile ? '解绑' : '绑定' }}</el-button>
</div>
<div class="mt-[30px] flex items-center justify-between">
<div class="flex items-center">
<img src="~/assets/images/qq-v2.png" alt="" srcset="" class="h-[35px] w-[34px]" />
<div class="ml-[19px] w-fit flex flex-col">
<div class="color-#333 text-15px mb-4px">QQ{{ user.qqOpenId ? '(已绑定)' : '' }}</div
><div class="color-#999">QQ可以用于登录帐号</div></div
>
</div>
<el-button :type="user.qqOpenId ? 'danger' : 'primary'" class="ml-10px" @click="handleBind('qq')">{{ user.qqOpenId ? '解绑' : '绑定' }}</el-button>
</div>
<div class="mt-[30px] flex items-center justify-between">
<div class="flex items-center">
<img src="~/assets/images/weixin-v2.png" alt="" srcset="" class="h-[35px] w-[34px]" />
<div class="ml-[19px] w-fit flex flex-col">
<div class="color-#333 text-15px mb-4px">微信{{ user.wxOpenId ? '(已绑定)' : '' }}</div
><div class="color-#999">微信可以用于登录帐号</div></div
>
</div>
<el-button :type="user.wxOpenId ? 'danger' : 'primary'" class="ml-10px" @click="handleBind('wx')">{{ user.wxOpenId ? '解绑' : '绑定' }}</el-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { Iphone } from '@element-plus/icons-vue'
import { onMounted } from 'vue'
import { handleLoginQQ, handleLoginWechat } from '~/utils/login'
import { getUserInfo, cancelSocialBind } from '~/api/personal-center/index'
import type { UserExtendRespVO } from '~/api/personal-center/types'
import { useMessage } from '~/composables/useMessage'
const message = useMessage()
onMounted(() => {
getUser()
})
const user = ref({} as UserExtendRespVO)
const getUser = async () => {
const res = await getUserInfo()
console.log(res)
user.value = res.data
}
const handleBind = async (type: string) => {
if (type === 'qq') {
if (user.value.qqOpenId) {
const res = await message.confirm('确定解绑QQ吗', '提示')
if (!res) return
cancelSocialBind({ type: 35, openid: user.value.qqOpenId }).then((res) => {
if (res.code === 0) {
ElMessage.success('解绑成功')
getUser()
}
})
} else {
handleLoginQQ()
}
}
if (type === 'wx') {
if (user.value.wxOpenId) {
const res = await message.confirm('确定解绑微信吗?', '提示')
if (!res) return
cancelSocialBind({ type: 32, openid: user.value.wxOpenId }).then((res) => {
if (res.code === 0) {
getUser()
ElMessage.success('解绑成功')
}
})
} else {
handleLoginWechat()
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,29 @@
<template>
<div class="box-border w-auto border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px mt-10px">
<el-button type="danger" @click="handleClick">注销账号</el-button>
</div>
</template>
<script setup lang="ts">
import useUserStore from '~/stores/user'
const userStore = useUserStore()
import { userLogout } from '~/api/personal-center/index'
const handleClick = () => {
console.log('注销账号')
ElMessageBox.confirm('确定注销账号吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
console.log('注销账号')
const res = await userLogout()
if (res.code === 0) {
ElMessage.success('注销成功')
navigateTo('/')
clearNuxtState(['token', 'userInfo'])
userStore.logout()
userStore.$reset()
}
})
}
</script>

View File

@ -0,0 +1,18 @@
<template>
<div class="box-border w-913px border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px">
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="个人资料" name="个人资料">
<PersonalProfile />
</el-tab-pane>
<el-tab-pane label="账户安全" name="账户安全">
<AccountSecurityV2 />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang="ts" setup>
import AccountSecurityV2 from './account-security-v2.vue'
import PersonalProfile from './personal-profile.vue'
const activeName = ref('个人资料')
</script>

View File

@ -0,0 +1,37 @@
<template>
<KlTabBar v-model="type" :data="tabBar" />
<div v-if="type === '修改密码'">
<AccountSecurity />
</div>
<div v-else-if="type === '账号绑定'">
<AccountBind />
</div>
<div v-else-if="type === '账号注销'">
<AccountLogout />
</div>
</template>
<script lang="ts" setup>
import KlTabBar from '~/components/kl-tab-bar/v2/index.vue'
import AccountSecurity from './account-security.vue'
import AccountBind from './account-bind.vue'
import AccountLogout from './account-logout.vue'
const tabBar = ref([
{
label: '修改密码',
value: '修改密码',
},
{
label: '账号绑定',
value: '账号绑定',
},
{
label: '账号注销',
value: '账号注销',
},
])
const type = ref('修改密码')
</script>
<style lang="scss" scoped></style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="box-border w-913px border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px"> <div class="box-border w-auto border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px mt-10px">
<el-tabs v-model="activeName" class="demo-tabs"> <!-- <el-tabs v-model="activeName" class="demo-tabs"> -->
<el-tab-pane label="修改密码" name="修改密码"> <!-- <el-tab-pane label="修改密码" name="修改密码"> -->
<el-form ref="formRef" :model="form" label-width="120px" class="profile-form" autocomplete="off"> <el-form ref="formRef" :model="form" label-width="120px" class="profile-form" autocomplete="off">
<el-form-item <el-form-item
label="手机号" label="手机号"
@ -19,7 +19,7 @@
<el-input v-model="form.phone" type="text" placeholder="请输入手机号" class="h-37px" /> <el-input v-model="form.phone" type="text" placeholder="请输入手机号" class="h-37px" />
</el-form-item> </el-form-item>
<el-form-item label="验证码" prop="code" class="mt-15px!" :rules="{ required: true, message: '请输入验证码', trigger: ['blur', 'change'] }"> <el-form-item label="验证码" prop="code" class="mt-15px!" :rules="{ required: true, message: '请输入验证码', trigger: ['blur', 'change'] }">
<div class="flex items-center gap10"> <div class="flex items-center gap-10px">
<el-input v-model="form.code" type="text" placeholder="请输入验证码" class="h-37px" /> <el-input v-model="form.code" type="text" placeholder="请输入验证码" class="h-37px" />
<el-button <el-button
type="primary" type="primary"
@ -46,9 +46,9 @@
<el-button type="primary" class="h-37px w-121px line-height-37px" @click="handleSave">保存</el-button> <el-button type="primary" class="h-37px w-121px line-height-37px" @click="handleSave">保存</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-tab-pane> <!-- </el-tab-pane> -->
<!-- <el-tab-pane label="登录设备管理" name="登录设备管理"> </el-tab-pane> --> <!-- <el-tab-pane label="登录设备管理" name="登录设备管理"> </el-tab-pane> -->
</el-tabs> <!-- </el-tabs> -->
</div> </div>
</template> </template>

View File

@ -5,7 +5,7 @@
<div class="flex items-center"> <div class="flex items-center">
<el-image :src="scope.row.url" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" /> <el-image :src="scope.row.url" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" />
<div class="ml-17px"> <div class="ml-17px">
<div class="text-16px text-[#333333] font-normal">{{ scope.row.title }}</div> <div class="text-14px font-normal">{{ scope.row.title }}</div>
</div> </div>
</div> </div>
</template> </template>

View File

@ -5,8 +5,8 @@
<div class="flex items-center"> <div class="flex items-center">
<el-image :src="scope.row.iconUrl" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" /> <el-image :src="scope.row.iconUrl" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" />
<div class="ml-17px"> <div class="ml-17px">
<div class="text-16px text-[#333333] font-normal">{{ scope.row.title }}</div> <div class="text-14px font-normal">{{ scope.row.title }}</div>
<div class="text-14px text-[#333333] font-normal my-10px!">by {{ scope.row?.ownedUserIdInfo?.nickName }}</div> <div class="text-13px font-normal my-10px!">by {{ scope.row?.ownedUserIdInfo?.nickName }}</div>
<div class="flex items-center"> <div class="flex items-center">
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" /> <img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" />

View File

@ -6,8 +6,8 @@
<div class="flex items-center"> <div class="flex items-center">
<el-image :src="scope.row.iconUrl" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" /> <el-image :src="scope.row.iconUrl" alt="" fit="cover" srcset="" class="h-91px w-181px rd-4px" />
<div class="ml-17px"> <div class="ml-17px">
<div class="text-16px text-[#333333] font-normal">{{ scope.row.title }}</div> <div class="text-14px font-normal">{{ scope.row.title }}</div>
<div class="text-14px text-[#333333] font-normal my-10px!">{{ scope.row?.ownedUserIdInfo?.nickName }}</div> <div class="text-13px font-normal my-10px!">{{ scope.row?.ownedUserIdInfo?.nickName }}</div>
<div class="flex items-center"> <div class="flex items-center">
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" /> <img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" />

View File

@ -17,7 +17,14 @@
<!-- 分页 --> <!-- 分页 -->
<div class="pagination mt-15px"> <div class="pagination mt-15px">
<el-pagination v-model:current-page="query.pageNo" :page-size="10" :total="result.total" background layout="prev, pager, next, jumper" /> <el-pagination
v-model:current-page="query.pageNo"
:page-size="10"
:total="result.total"
background
layout="prev, pager, next, jumper"
@current-change="handeClickCurrent"
/>
</div> </div>
</template> </template>
@ -51,6 +58,12 @@
} }
} }
getTradeRecords() getTradeRecords()
// 点击分页
const handeClickCurrent = (pageNo: number) => {
query.pageNo = pageNo
getTradeRecords()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-pagination) { :deep(.el-pagination) {

View File

@ -11,12 +11,12 @@
<!-- <div class="vip-card-subtitle">中小微企业</div> --> <!-- <div class="vip-card-subtitle">中小微企业</div> -->
</div> </div>
<div class="vip-card-price"> <div class="vip-card-price">
<span class="price">{{ accDiv(item.payPrice || 0, 100) }}</span> <span class="price">{{ item.payPrice }}</span>
<!-- <span class="per">/1</span> --> <!-- <span class="per">/1</span> -->
</div> </div>
<ul class="vip-card-features"> <ul class="vip-card-features">
<li <li
>赠送<span class="color-red">{{ accDiv(item.bonusPrice || 0, 100) }}</span></li >赠送<span class="color-red">{{ item.bonusPrice }}</span></li
> >
<!-- <li>1. {{ item.profile }}</li> <!-- <li>1. {{ item.profile }}</li>
<li <li
@ -39,7 +39,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, onMounted } from 'vue' import { ref, watch, onMounted } from 'vue'
import { listWalletRechargePackage, submitPayOrder, getPayStatus } from '~/api/pay/index' import { listWalletRechargePackage, submitPayOrder, getPayStatus } from '~/api/pay/index'
import { accDiv } from '~/utils/utils' // import { accDiv } from '~/utils/utils'
import { Close } from '@element-plus/icons-vue' import { Close } from '@element-plus/icons-vue'
import type { AppPayWalletPackageRespVO } from '~/api/pay/types' import type { AppPayWalletPackageRespVO } from '~/api/pay/types'
// @ts-ignore // @ts-ignore
@ -155,8 +155,10 @@
.vip-cards { .vip-cards {
display: flex; display: flex;
gap: 32px; gap: 32px;
justify-content: center; /* justify-content: center; */
margin: 24px 0; margin: 24px 0;
overflow-x: auto;
padding: 10px;
} }
.vip-card { .vip-card {
background: #fff; background: #fff;
@ -169,6 +171,7 @@
align-items: center; align-items: center;
padding-bottom: 70px; padding-bottom: 70px;
position: relative; position: relative;
flex-shrink: 0;
} }
.vip-card-header { .vip-card-header {
width: 100%; width: 100%;

View File

@ -4,10 +4,13 @@
<el-table-column prop="date" label="文件信息"> <el-table-column prop="date" label="文件信息">
<template #default="scope"> <template #default="scope">
<div class="flex items-center"> <div class="flex items-center">
<el-image :src="scope.row.iconUrl" fit="cover" alt="" srcset="" class="h-91px w-181px rd-4px" /> <el-image :src="scope.row.iconUrl" fit="contain" alt="" srcset="" class="h-91px w-181px rd-4px" />
<div class="ml-17px"> <div class="ml-17px">
<div class="text-16px text-[#333333] font-normal">{{ scope.row.title }}</div> <div class="text-14px">{{ scope.row.title }}</div>
<div class="text-14px text-[#333333] font-normal my-10px!">{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</div> <div class="text-13px my-10px!">
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
<span class="ml-4px color-#999">{{ scope.row.isDomestic === 1 ? '中国' : scope.row.country }}</span>
</div>
<div class="flex items-center"> <div class="flex items-center">
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" /> <img src="~/assets/images/look.png" alt="" srcset="" class="h-17px" />
@ -34,7 +37,9 @@
<el-table-column prop="address" label="操作" width="100"> <el-table-column prop="address" label="操作" width="100">
<template #default="scope"> <template #default="scope">
<el-link v-if="scope.row.status === 4" type="primary" :underline="false" @click="handleXiaJia(scope.row)">下架</el-link> <el-link v-if="scope.row.status === 4" type="primary" :underline="false" @click="handleXiaJia(scope.row)">下架</el-link>
<el-link type="primary" :underline="false" @click="handleDelete(scope.row)">删除</el-link> <el-link type="danger" :underline="false" @click="handleDelete(scope.row)" class="mr-4px">删除</el-link>
<el-link type="primary" :underline="false" @click="handlePreview(scope.row)">查看</el-link>
<el-link type="primary" :underline="false" @click="handleEdit(scope.row)" class="mt-4px">编辑</el-link>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -78,6 +83,10 @@
label: '文本', label: '文本',
value: 2, value: 2,
}, },
{
label: '工具箱',
value: 4,
},
]) ])
const handleStatus = (status: number) => { const handleStatus = (status: number) => {
@ -85,11 +94,11 @@
case 1: case 1:
return '草稿' return '草稿'
case 2: case 2:
return '提交审核' return '审核'
case 3: case 3:
return '审核成功' return '发布成功'
case 4: case 4:
return '下架' return '退稿'
default: default:
return '' return ''
} }
@ -114,6 +123,14 @@
} }
}) })
} }
const handlePreview = (row: any) => {
navigateTo(`/upnew?id=${row.id}&projectId=${row.projectId}&type=preview`)
}
const handleEdit = (row: any) => {
navigateTo(`/upnew?id=${row.id}&projectId=${row.projectId}&type=edit`)
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -1,12 +1,14 @@
<template> <template>
<div class="box-border w-[913px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] px-[30px] py-[18px]"> <div class="box-border w-[913px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] px-[30px] py-[18px]">
<div class="flex items-center"> <div class="flex items-center">
<img :src="userStore.userInfoRes.avatar" alt="" srcset="" class="h-[105px] w-[105px] rounded-full" /> <div class="relative">
<img :src="userStore.userInfoRes.avatar" alt="" srcset="" class="h-[105px] w-[105px] rounded-full" />
<img v-if="userStore.userInfoRes.vipLevel === 1" src="~/assets/svg/vip.svg" alt="" class="absolute bottom-[0px] right-[4px]" />
<img v-if="userStore.userInfoRes.vipLevel === 2" src="~/assets/svg/svip.svg" alt="" class="absolute bottom-[0px] right-[5px]" />
</div>
<div class="ml-[29px]"> <div class="ml-[29px]">
<div class="flex items-center"> <div class="flex items-center">
<span class="text-[20px] text-[#333333] font-normal">Hi{{ userStore.userInfoRes.nickname }}</span> <span class="text-[20px] text-[#333333] font-normal">Hi{{ userStore.userInfoRes.nickname }}</span>
<img v-if="userStore.userInfoRes.vipLevel === 1" src="~/assets/svg/vip.svg" alt="" class="relative top-[2px] ml-[5px]" />
<img v-if="userStore.userInfoRes.vipLevel === 2" src="~/assets/svg/svip.svg" alt="" class="relative top-[2px] ml-[5px]" />
<div <div
class="ml-[18px] h-[30px] w-[80px] cursor-pointer border border-[#1A65FF] rounded-[15px] border-solid text-center text-[14px] text-[#1A65FF] font-normal line-height-[30px]" class="ml-[18px] h-[30px] w-[80px] cursor-pointer border border-[#1A65FF] rounded-[15px] border-solid text-center text-[14px] text-[#1A65FF] font-normal line-height-[30px]"
@click="handleClick" @click="handleClick"
@ -16,7 +18,7 @@
<div class="mt-[20px] flex items-center text-[14px] text-[#333333] font-normal"> <div class="mt-[20px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/cad_0 (1).png" alt="" srcset="" /> <img src="~/assets/images/cad_0 (1).png" alt="" srcset="" />
<span class="ml-[4px]">我的积分: {{ userStaticInfo?.pointCount || 0 }}</span> <span class="ml-[4px]">我的金币: {{ userStaticInfo?.pointCount || 0 }}</span>
</div> </div>
<div class="ml-[37px] flex items-center"> <div class="ml-[37px] flex items-center">
<img src="~/assets/images/cad_0 (2).png" alt="" srcset="" /> <img src="~/assets/images/cad_0 (2).png" alt="" srcset="" />
@ -123,7 +125,7 @@
fetchUserStatistics() fetchUserStatistics()
const handleClick = () => { const handleClick = () => {
router.push({ path: '/personal-Center/personal-profile' }) router.push({ path: '/personal-center/account-management' })
} }
const payVisible = ref(false) const payVisible = ref(false)

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="box-border h-[782px] w-[913px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] px-[30px] py-[21px]"> <div class="box-border h-[682px] w-[913px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] px-[30px] py-[21px]">
<div class="flex items-center justify-between border-b-[1px] border-b-[#eeeeee] border-b-solid pb-[18px]"> <!-- <div class="flex items-center justify-between border-b-[1px] border-b-[#eeeeee] border-b-solid pb-[18px]">
<div class="text-[16px] text-[#333333] font-normal">个人资料</div> <div class="text-[16px] text-[#333333] font-normal">个人资料</div>
<div class="flex items-center"> <div class="flex items-center">
<!-- <img src="~/assets/images/fans.png" alt="" srcset="" /> --> <img src="~/assets/images/fans.png" alt="" srcset="" />
<span class="ml-[8px] text-[14px] text-[#333333] font-normal"></span> <span class="ml-[8px] text-[14px] text-[#333333] font-normal"></span>
</div> </div>
</div> </div> -->
<div class="user-profile-container"> <div class="user-profile-container">
<div class="avatar-section"> <div class="avatar-section">
<el-upload class="avatar-uploader" action="#" :show-file-list="false" :auto-upload="false" :on-change="handleAvatarChange"> <el-upload class="avatar-uploader" action="#" :show-file-list="false" :auto-upload="false" :on-change="handleAvatarChange">
@ -22,7 +22,7 @@
<!-- User avatar section --> <!-- User avatar section -->
<!-- User information section --> <!-- User information section -->
<el-form-item label="用户名:" prop="nickname"> <el-form-item label="用户名:" prop="nickname" :rules="[{ required: true, message: '请输入用户名', trigger: 'blur' }]">
<div class="flex items-center"> <div class="flex items-center">
<el-input v-model="userForm.nickname" class="w-[247px]" /> <el-input v-model="userForm.nickname" class="w-[247px]" />
<el-button type="primary" class="verify-btn" @click="handleVerify">实名认证</el-button> <el-button type="primary" class="verify-btn" @click="handleVerify">实名认证</el-button>
@ -36,14 +36,14 @@
</div> </div>
</el-form-item> --> </el-form-item> -->
<el-form-item label="手机号:" prop="phone"> <el-form-item label="手机号:" prop="phone" :rules="[{ required: true, message: '请输入手机号', trigger: 'blur' }]">
<div class="flex items-center"> <div class="flex items-center">
<el-input v-model="userForm.phone" disabled class="w-[247px]" /> <el-input v-model="userForm.phone" disabled class="w-[247px]" />
<!-- <el-link type="primary" class="modify-link">修改</el-link> --> <!-- <el-link type="primary" class="modify-link">修改</el-link> -->
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="电子邮箱:" prop="email"> <el-form-item label="电子邮箱:" prop="email" :rules="[{ required: true, message: '请输入电子邮箱', trigger: 'blur' }]">
<div class="flex items-center"> <div class="flex items-center">
<el-input v-model="userForm.email" placeholder="请输入电子邮箱" class="w-[247px]" /> <el-input v-model="userForm.email" placeholder="请输入电子邮箱" class="w-[247px]" />
<!-- <el-link type="primary" class="modify-link">绑定</el-link> --> <!-- <el-link type="primary" class="modify-link">绑定</el-link> -->
@ -51,30 +51,30 @@
</el-form-item> </el-form-item>
<div class="flex items-center"> <div class="flex items-center">
<el-form-item label="所在地区:" prop="isDomestic"> <el-form-item label="所在地区:" prop="isDomestic" :rules="[{ required: false, message: '请选择所在地区', trigger: 'change' }]">
<el-select v-model="userForm.isDomestic" placeholder="请选择" class="w-[120px]!" @change="handleCountryChange"> <el-select v-model="userForm.isDomestic" placeholder="请选择" class="w-[120px]!" @change="handleCountryChange">
<el-option label="国内" :value="1"></el-option> <el-option label="国内" :value="1"></el-option>
<el-option label="国外" :value="0"></el-option> <el-option label="国外" :value="0"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label-width="6px" prop="province"> <el-form-item label-width="6px" prop="province" :rules="[{ required: false, message: '请选择省份', trigger: 'change' }]">
<el-select v-model="userForm.province" placeholder="请选择省份" class="w-[120px]!" @change="handleProvinceChange"> <el-select v-model="userForm.province" placeholder="请选择省份" class="w-[120px]!">
<el-option v-for="item in provinceList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in provinceList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label-width="6px" prop="city"> <!-- <el-form-item label-width="6px" prop="city" :rules="[{ required: true, message: '请选择城市', trigger: 'change' }]">
<el-select v-model="userForm.city" placeholder="请选择城市" class="w-[120px]!" @change="handleCityChange"> <el-select v-model="userForm.city" placeholder="请选择城市" class="w-[120px]!" @change="handleCityChange">
<el-option v-for="item in cityList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in cityList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label-width="6px" prop="county"> <el-form-item label-width="6px" prop="county" :rules="[{ required: true, message: '请选择区县', trigger: 'change' }]">
<el-select v-model="userForm.county" placeholder="请选择区县" class="w-[120px]!"> <el-select v-model="userForm.county" placeholder="请选择区县" class="w-[120px]!">
<el-option v-for="item in countyList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in countyList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
</div> </div>
<el-form-item label="技能标签:" prop="labels"> <el-form-item label="技能标签:" prop="labels" :rules="[{ required: false, message: '请选择技能标签', trigger: 'change' }]">
<el-select <el-select
v-model="userForm.labels" v-model="userForm.labels"
:remote-method="remoteMethod" :remote-method="remoteMethod"
@ -89,7 +89,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="技能证书:" prop="files"> <el-form-item label="技能证书:" prop="files" :rules="[{ required: false, message: '请上传技能证书', trigger: 'change' }]">
<KlUploader <KlUploader
v-model:file-list="userForm.files" v-model:file-list="userForm.files"
list-type="picture-card" list-type="picture-card"
@ -104,12 +104,13 @@
</KlUploader> </KlUploader>
</el-form-item> </el-form-item>
<el-form-item label="个人简介:" prop="description"> <el-form-item label="个人简介:" prop="description" :rules="[{ required: true, message: '请输入个人简介', trigger: 'blur' }]">
<el-input v-model="userForm.description" type="textarea" :rows="5" placeholder="请输入个人简介" class="full-width" /> <el-input v-model="userForm.description" type="textarea" :rows="5" placeholder="请输入个人简介" class="full-width" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item class="relative">
<el-button type="primary" class="w-[120px] !h-[37px]" :loading="submitLoading" @click="submitForm">提交</el-button> <el-button type="primary" class="w-[120px] !h-[37px]" :loading="submitLoading" @click="submitForm">提交</el-button>
<div class="absolute top-[40px] left-[0] text-[12px] text-[#999999] font-normal">温馨提示更改头像需要重新登录生效</div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -158,7 +159,7 @@
province: '', province: '',
county: '', county: '',
labels: [], labels: [],
description: '', description: '这个工程师很懒 什么都没写',
authStatus: 0, authStatus: 0,
files: [], files: [],
nickname: '', nickname: '',
@ -314,11 +315,11 @@
userForm.country = res.data.country userForm.country = res.data.country
await getAdress('province', userForm.isDomestic) await getAdress('province', userForm.isDomestic)
// @ts-ignore // @ts-ignore
userForm.province = +res.data.province userForm.province = res.data.province
await getAdress('city', userForm.province) // await getAdress('city', userForm.province)
// @ts-ignore // @ts-ignore
userForm.city = +res.data.city userForm.city = +res.data.city
await getAdress('county', userForm.city) // await getAdress('county', userForm.city)
// @ts-ignore // @ts-ignore
userForm.county = +res.data.county userForm.county = +res.data.county
userForm.labels = res.data.labels userForm.labels = res.data.labels

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="box-border min-h-494px w-913px border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px"> <div class="box-border w-913px border border-[#EEEEEE] rounded-6px border-solid bg-[#FFFFFF] px-30px py-21px">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="我的上传" name="我的上传"> <el-tab-pane label="我的上传" name="我的上传">
<uploadTable v-model:type="pageReq.type" v-model="result.list" :refresh="handlerefresh" /> <uploadTable v-model:type="pageReq.type" v-model="result.list" :refresh="handlerefresh" />

View File

@ -1,28 +1,55 @@
<template> <template>
<div class="account-balance"> <div class="account-balance">
<!-- 余额展示区域 --> <!-- 余额展示区域 -->
<div class="balance-section"> <div class="balance-section flex h-206px!">
<div class="balance-title"> <div>
<span>我的金币</span> <div class="balance-title">
<el-tag size="small" type="primary">资产和使用</el-tag> <span>我的金币</span>
<el-tag size="small" type="primary">资产和使用</el-tag>
</div>
<div class="balance-amount">{{ userStaticInfo?.currencyCount || 0 }}</div>
<div class="balance-actions">
<el-button type="primary" @click="handlePay">充值</el-button>
<el-button type="danger" @click="handleWithdraw">提现</el-button>
<el-button type="warning">兑换</el-button>
</div>
<div class="balance-tip">提示最低提现金额100 一元=10金币</div>
</div> </div>
<div class="balance-amount">{{ userStaticInfo?.currencyCount || 0 }}</div> <el-divider direction="vertical" class="h-100%! mx-30px!" border-style="dashed"></el-divider>
<div class="balance-actions"> <div>
<el-button type="primary" @click="handlePay">充值</el-button> <div class="balance-title">
<el-button>提现</el-button> <span>我的收益</span>
<el-tag size="small" type="primary">收益金币数额展示</el-tag>
</div>
<div class="balance-amount">{{ userStaticInfo?.revenueBalance || 0 }}</div>
<div class="balance-actions">
<!-- <el-button type="primary" @click="handlePay">充值</el-button>
<el-button>提现</el-button> -->
</div>
<!-- <div class="balance-tip">提示最低提现金额100 一元=10金币</div> -->
</div> </div>
<div class="balance-tip">提示最低提现金额100 一元=10金币</div>
</div> </div>
<!-- 广告海报swiper -->
<el-carousel height="150px" class="rounded-[8px] rounded-[6px] border border-solid border-[#eeeeee] box-borders mb-20px">
<el-carousel-item>
<el-image src="https://static.tuxixi.net/tuxixi_banner3.png" alt="" class="w-100%" fit="contain" />
</el-carousel-item>
<el-carousel-item>
<el-image src="https://static.tuxixi.net/tuxixi_banner2.jpg" alt="" class="w-100%" fit="cover" />
</el-carousel-item>
</el-carousel>
<!-- 交易记录区域 --> <!-- 交易记录区域 -->
<div class="transaction-section"> <div class="transaction-section">
<div class="transaction-tabs"> <div class="transaction-tabs">
<el-tabs v-model="activeTab"> <el-tabs v-model="activeTab">
<el-tab-pane label="充值记录" name="purchase"> <el-tab-pane label="交易记录" name="purchase">
<!-- 组件 --> <!-- 组件 -->
<PayRecords></PayRecords> <PayRecords></PayRecords>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="提现管理" name="withdraw"></el-tab-pane> <el-tab-pane label="提现管理" name="withdraw">
<div class="text-center color-#999 pa-10px">暂无数据</div>
</el-tab-pane>
</el-tabs> </el-tabs>
<!-- <div class="date-filter"> <!-- <div class="date-filter">
<span>当前时期</span> <span>当前时期</span>
@ -30,8 +57,14 @@
</div> --> </div> -->
</div> </div>
</div> </div>
<!-- 提示 -->
<div class="color-red pa-10px text-13px">
温馨提示交易未到账紧急联系客服,金币为虚拟积分不支持退款,但支持高额手续费提现抵制恶性充值提现操作金币使用没有时间限制,平台作品交易仅供学习参考,用于商业用途请与原作者联系!
</div>
<!-- 充值弹窗 --> <!-- 充值弹窗 -->
<Pay v-if="payVisible" v-model="payVisible" @refresh="fetchUserStatistics"></Pay> <Pay v-if="payVisible" v-model="payVisible" @refresh="fetchUserStatistics"></Pay>
<!-- 提现弹窗 -->
<Withdraw v-if="withdrawVisible" v-model="withdrawVisible"></Withdraw>
</div> </div>
</template> </template>
@ -58,12 +91,18 @@
payVisible.value = true payVisible.value = true
// router.push({ path: '/personal/trading/center' }) // router.push({ path: '/personal/trading/center' })
} }
const withdrawVisible = ref(false)
const handleWithdraw = () => {
withdrawVisible.value = true
// router.push({ path: '/personal/trading/center' })
}
</script> </script>
<style scoped> <style scoped>
.account-balance { .account-balance {
width: 913px; width: 913px;
min-height: 100vh; /* min-height: 100vh; */
background: #ffffff; background: #ffffff;
} }

View File

@ -62,6 +62,7 @@
source: source.value || -1, source: source.value || -1,
type: 2, type: 2,
title: keywords.value, title: keywords.value,
recommend: source.value === -1 ? true: false,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -93,6 +94,7 @@
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -53,6 +53,7 @@
editions: '-1', editions: '-1',
source: -1, source: -1,
type: 2, type: 2,
recommend: true,
}) })
// const result = reactive<pageRes>({ // const result = reactive<pageRes>({
// list: [], // list: [],
@ -65,13 +66,14 @@
} }
const { data: result } = useAsyncData( const { data: result } = useAsyncData(
`draw-page-list-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}`, `draw-page-list-text-${query.value.projectType}-${query.value.editions}-${query.value.source}-${query.value.pageNo}-${query.value.pageSize}`,
async () => { async () => {
const res = await page({ const res = await page({
...query.value, ...query.value,
editions: query.value.editions === '-1' ? '' : query.value.editions, editions: query.value.editions === '-1' ? '' : query.value.editions,
source: query.value.source === -1 ? '' : query.value.source, source: query.value.source === -1 ? '' : query.value.source,
projectType: query.value.projectType === '-1' ? '' : query.value.projectType, projectType: query.value.projectType === '-1' ? '' : query.value.projectType,
recommend: query.value.source === -1 ? true: false,
}) })
return res.data return res.data
}, },

View File

@ -0,0 +1,338 @@
<template>
<SeoHead :title="detail?.title" :description="detail?.description" :keywords="detail?.labels?.toString()" />
<KlNavTab />
<!-- <div v-if="breadList && breadList.length > 1" class="mb-[-10px] mt-[20px] w-[1440px] mx-auto">
<el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">{{ item.name }}</el-breadcrumb-item>
</el-breadcrumb>
</div> -->
<div class="ml-auto mr-auto mt-[20px] w-[1440px]">
<div class="flex items-center">
<div
class="box-border h-[60px] w-[1019px] flex items-center justify-between border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[27px] py-[24px]"
>
<div class="text-[16px] text-[#333333] font-normal"> {{ detail?.title }}</div>
<div class="flex items-center">
<img :src="detail?.ownedUserAvatar" alt="" srcset="" class="h-[30px] w-[30px] rd-[50%]" />
<span class="ml-[8px] color-[#999999]">by {{ detail?.ownedUserName }}</span>
</div>
</div>
<div class="ml-[23px] flex flex-1 text-[16px] text-[#FFFFFF] font-normal">
<div class="h-[60px] w-[160px] flex cursor-pointer items-center justify-center rounded-[8px] bg-[#1A65FF]" @click="handleDownload">
<img src="~/assets/images/download.png" alt="" srcset="" class="mr-[4px] h-[22px] w-[27px]" />
{{ detail?.points === 0 ? '免费下载' : '立即下载' }}
</div>
<div
v-if="!detail?.favoriteId"
class="ml-[11px] h-[60px] flex flex-1 cursor-pointer items-center justify-center rounded-[8px] bg-[#E7B03B]"
@click="handleCollect"
><img src="~/assets/images/collect.png" alt="" srcset="" class="mr-[4px] h-[24px] w-[24px]" /> 收藏</div
>
<div v-else class="ml-[11px] h-[60px] flex flex-1 cursor-pointer items-center justify-center rounded-[8px] bg-[#E7B03B]" @click="handleCollect"
><img src="~/assets/images/wjx2.png" alt="" srcset="" class="mr-[4px] h-[18px] w-[18px]" /> 已收藏</div
>
<div class="ml-[11px] h-[60px] flex flex-1 cursor-pointer items-center justify-center rounded-[8px] bg-[#F56C6C]" @click="handleReport"
><el-icon class="mr-[4px] mt-[4px]"><Warning /></el-icon> 举报</div
>
</div>
</div>
</div>
<!-- -->
<div class="ma-auto mt-[21px] flex">
<div class="w-[1019px]">
<div>
<ThumBnail :data="detail?.coverImages"></ThumBnail>
</div>
<div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">工具使用介绍</span></div
>
<div
class="box-border min-h-[90px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px] text-[14px] text-[#333333] font-normal"
>
{{ detail?.description }}
</div>
<div id="section1" class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div><span class="ml-[10px]">工具文件</span></div
>
<div class="box-border w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[24px]">
<div class="border-b-[1px] border-b-[#eee] border-b-solid p-b-[10px]"> 包含的文件 </div>
<div>
<div v-for="item in detail?.files" :key="item.id" class="flex items-center justify-between border-b-[1px] border-b-[#eee] border-b-solid py-[10px]">
<!-- <img src="~/assets/images/avater.png" alt="" srcset="" class="h-30px w-30px" /> -->
<div>
<!-- <span class="ml-[10px] cursor-pointer" @click="handleDownloadPreview(item)">{{ item.title }}</span> -->
<span class="ml-[10px]">{{ item.title }}</span>
<span v-if="item.size" class="ml-[200px] color-[#999]">{{ item.size || '-' }}</span>
</div>
<el-button
v-if="detail?.downloadId || detail?.points === 0"
type="text"
tag="a"
target="download"
:href="item.url"
@click="handleDownloadFile(item.url, item.title)"
>
下载
</el-button>
</div>
</div>
</div>
<!-- 评论 -->
<CommentSection :relation-id="detail!.id" />
</div>
<div class="ml-[22px]">
<div class="box-border min-h-[180px] w-[397px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] pa-[22px]">
<div class="mb-[10px]">工具ID: {{ detail?.no }}</div>
<!-- <div class="mb-[10px]">文件大小{{ detail?.filesInfo?.fileSize || 0 }} </div> -->
<!-- <div class="mb-10px">图纸版本{{ detail.editionsName }} </div> -->
<!-- <div class="mb-[10px]">工具格式{{ detail?.formatType?.toString() }}</div> -->
<div class="mb-[10px]">所需金币{{ detail?.points }}金币</div>
<div class="mb-[10px]">发布时间{{ dayjs(detail?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</div>
<!-- <div class="mb-[10px]">工具参数{{ detail?.editTypeName }}</div> -->
<div class="mb-[10px]">工具标签{{ detail?.labels?.toString() }}</div>
<div class="mb-[10px]">软件分类{{ detail?.categoryName }}</div>
</div>
<div class="mt-[20px] w-[398px] border border-[#EEEEEE] border-rd-[10px_10px_0px_0px] border-solid bg-[#FFFFFF]">
<img src="~/assets/images/banner.png" alt="" srcset="" class="w-[100%]" />
<div class="box-border border border-[#EEEEEE] border-rd-[10px_10px_0px_0px] border-solid border-t-none bg-[#FFFFFF] pa-[18px]">
<div class="flex flex-wrap items-start">
<div v-if="userInfo?.nickname" class="text-[18px] text-[#333333] font-bold">{{ userInfo.nickname }}</div>
<div
v-for="item in userInfo?.labels"
:key="item"
class="mb-[10px] ml-[10px] box-border border border-[#1A65FF] rounded-[13px] border-solid px-[8px] py-[3px] color-[#1a65ff]"
>{{ item }}</div
>
</div>
<div v-if="userInfo?.description" class="mb-[20px] text-[14px] text-[#333333] font-normal">{{ userInfo.description }}</div>
<!-- 显示作品 粉丝 荣誉证书 -->
<div class="flex items-center gap-[40px]">
<div class="flex items-center">
<div class="h-[20px]">
<img src="~/assets/images/folder.png" alt="works" class="w-[80%]" />
</div>
<div class="ml-[8px] mt-[-4px] text-[14px] text-[#666] font-normal">作品: {{ userInfo?.projectCount || 0 }}</div>
</div>
<div class="flex items-center">
<div class="h-[20px]">
<img src="~/assets/images/user4.png" alt="fans" class="w-[80%] rounded-full vertical-top" />
</div>
<div class="relative top-[-3px] ml-[8px] text-[14px] text-[#666] font-normal">发帖数: {{ userInfo?.fansCount || 0 }}</div>
</div>
</div>
<!-- 3个图片一排 超过换下一行 -->
<div v-if="userInfo?.files?.length" class="mt-[20px] flex flex-wrap gap-[16px]">
<div v-for="i in userInfo.files" :key="i" class="flex-1">
<div
class="box-border h-[200px] w-full overflow-hidden border border-[#E5E7EB] rounded-[8px] border-solid from-[#FFFFFF] to-[#F5F7FA] bg-gradient-to-b p-[16px]"
>
<el-image :src="i.url" fit="cover" alt="" srcset="" class="h-full object-cover" />
</div>
</div>
</div>
<div class="mt-[20px] h-[1px] w-[336px] rounded-[1px] bg-[#EEEEEE]"></div>
<div class="mt-[20px] flex items-center">
<div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div>
<span class="ml-[10px] text-[14px]">最新发布</span>
</div>
<div class="mt-[10px]">
<div
v-for="item in mainWork"
:key="item.id"
class="flex cursor-pointer items-center justify-between px-[10px] py-[10px] hover:bg-[#f5f5f5]"
@click="handleClick(item.id)"
>
<div class="ellipsis text-[15px] text-[#333333] font-normal">{{ item.title }}</div>
<span class="ml-[10px] flex-shrink-0 color-[#999999]">{{ dayjs(item.createTime).format('MM-DD') }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs'
import { ArrowRight } from '@element-plus/icons-vue'
import { downloadFile } from '~/utils/utils'
import { useMessage } from '~/utils/useMessage'
import { Warning } from '@element-plus/icons-vue'
import SeoHead from '~/components/seo-head/index.vue'
import CardPicture from '~/components/kl-card-picture/index.vue'
import { getDictTree } from '~/api/home/index'
import { get } from '@/api/toolbox/index'
import { getDetail, getRelationRecommend, report, getToolUserInfo, getMainWork, createContent, createUserProject, deleteProject } from '~/api/drawe-detail/index'
import KlNavTab from '~/components/kl-nav-tab/index.vue'
import ThumBnail from './components/swiper.vue'
import CommentSection from '~/components/comment-section/index.vue'
import { useRoute } from 'vue-router'
import useUserStore from '~/stores/user'
const message = useMessage()
const userStore = useUserStore()
// 获取路由参数
const route = useRoute()
const id = route.params.id as string
const { data: detail, refresh: refreshDetail } = await useAsyncData(`toolbox-getDetail${id}`, async () => {
const res = await get({ id: id as string })
return res.data
})
console.log('==', detail.value)
if (!detail.value) {
throw createError({
statusCode: 404,
statusMessage: 'Page Not Found',
fatal: true,
})
}
// init()
const [{ data: mainWork }, { data: userInfo }] = await Promise.all([
getMainWork({ id: detail.value?.id, limit: 10, memberId: detail.value?.ownedUserId }),
getToolUserInfo({ id: detail.value?.id }),
])
// 获取最新发布
// const mainWork = ref<ProjectDrawMemberRespVO[]>([])
// const handleGetMainWork = () => {
// getMainWork({ id: detail.value?.id, limit: 10, memberId: detail.value?.ownedUserId }).then((res) => {
// if (res.code === 0) {
// mainWork.value = res.data
// }
// })
// }
// 获取用户信息
// const userInfo = ref<UserExtendSimpleRespDTO>({} as UserExtendSimpleRespDTO)
// const handleGetUserInfo = () => {
// getUserInfo({ id: detail.value?.id }).then((res) => {
// if (res.code === 0) {
// userInfo.value = res.data
// }
// })
// }
// 获取关联推荐
// const relationRecommend = ref<ProjectDrawPageRespVO[]>([])
// const getRelationRecommendList = () => {
// getRelationRecommend({ type: detail.value?.type, projectType: detail.value?.projectType[0] }).then((res) => {
// if (res.code === 0) {
// relationRecommend.value = res.data
// }
// })
// }
const handleDownloadPreview = (item: any) => {
// 预览pdf
navigateTo(`/pdf-preview?url=${item.url}`)
}
/** 获取下载类型 */
const getType = (type: number) => {
if (type === 1 || type === 2 || type === 3) {
// 图纸 文本 模型都传1
return 1
}
// 工具箱传
return 2
}
const handleDownload = async () => {
if (!userStore.token) {
ElMessage.error('请先登录')
return
}
if (detail.value?.points === 0) {
scrollTo()
return
}
if (detail.value?.downloadId) {
ElMessage.success('您已获取下载权限')
scrollTo()
return
}
const res = await message.confirm(`是否花费${detail.value?.points}金币下载此资源,是否继续?`, '提示')
if (res) {
createUserProject({ relationId: detail.value?.id, type: 2 }).then((res) => {
if (res.code === 0) {
ElMessage.success('获取下载权限成功')
detail.value!.downloadId = res.data
scrollTo()
}
})
}
}
const scrollTo = () => {
const element = document.getElementById('section1')
if (element) {
element.scrollIntoView({
behavior: 'smooth',
})
}
}
const handleReport = () => {
if (!userStore.token) {
ElMessage.error('请先登录')
return
}
console.log('举报')
ElMessageBox.prompt('说明内容', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPlaceholder: '请输入举报内容',
inputErrorMessage: '请输入举报内容',
}).then(({ value }) => {
report({
id: detail.value?.id,
title: detail.value?.title,
files: detail.value?.files,
comments: value,
drawId: detail.value?.id,
type: 4,
}).then((res) => {
if (res.code === 0) {
ElMessage.success('举报成功')
}
})
})
}
const handleCollect = async () => {
if (!userStore.token) {
ElMessage.error('请先登录')
return
}
const res = detail.value?.favoriteId
? await deleteProject({ id: detail.value.favoriteId })
: await createContent({
drawId: detail.value?.id,
type: 4,
})
if (res.code === 0) {
ElMessage.success(`${detail.value?.favoriteId ? '取消' : '收藏'}成功`)
refreshDetail()
}
}
const handleClick = (id: string | number) => {
navigateTo(`/toolbox-detail/${id}`) // 修改为在新窗口打开
}
const handleDownloadFile = (url: string, name: string) => {
downloadFile(url, name)
}
</script>

View File

@ -0,0 +1,163 @@
<template>
<div class="box-border h-[631px] w-[1019px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] pa-[30px]">
<div style="--swiper-navigation-color: #fff; --swiper-pagination-color: #fff" class="swiper mySwiper2">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(item, index) in props.data" :key="index">
<img :src="item.url" />
</div>
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<div class="mb-[20px] mt-[34px] flex items-center text-[14px] text-[#333333] font-normal">
<div class="h-[20px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div>
<span class="ml-[10px]">工具截图</span>
</div>
<div class="box-border h-[126px] w-[1019px] border border-[#EEEEEE] rounded-[6px] border-solid bg-[#FFFFFF] pa-[23px]">
<div thumbsSlider="" class="swiper mySwiper">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(item, index) in props.data" :key="index">
<img :src="item.url" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { PropType } from 'vue'
import { ref, watch, nextTick, onMounted } from 'vue'
const props = defineProps({
data: {
type: Array as PropType<any[]>,
default: () => [],
},
type: {
type: Number as PropType<number>,
default: 1,
},
})
onMounted(() => {
// Initialize Swiper
// @ts-ignore
var swiper = new Swiper('.mySwiper', {
spaceBetween: 10,
slidesPerView: 4,
freeMode: true,
watchSlidesProgress: true,
})
// @ts-ignore
var swiper2 = new Swiper('.mySwiper2', {
spaceBetween: 10,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
thumbs: {
swiper: swiper,
},
})
})
</script>
<style scoped>
.swiper-button-disabled {
cursor: pointer !important;
}
.swiper {
width: 100%;
height: 100%;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: flex;
justify-content: center;
align-items: center;
}
.swiper-slide img {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
pointer-events: none;
}
.swiper {
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
background-size: cover;
background-position: center;
}
.mySwiper2 {
height: 100%;
/* height: calc(100vh - 207px); */
/* width: 100%; */
}
.mySwiper {
height: 90px;
box-sizing: border-box;
padding: 6px 6px;
/* position: absolute;
bottom: 0;
left: 0px;
right: 0px !important; */
background: rgba(0, 0, 0, 0.65);
/* z-index: 1000; */
/* width: 100%; */
}
.mySwiper .swiper-slide {
width: 25%;
height: 100%;
opacity: 0.4;
background: rgba(0, 0, 0, 0.65);
cursor: pointer;
}
.mySwiper .swiper-slide-thumb-active {
opacity: 1;
}
.swiper-slide img {
display: block;
/* width: 100%; */
height: 100%;
object-fit: contain;
pointer-events: none;
}
.Thumbs {
position: relative;
height: 100%;
width: auto;
background: rgba(0, 0, 0, 0.65);
}
.Thumbs img {
height: 100%;
pointer-events: none;
}
.swiper-button-next,
.swiper-button-prev {
color: #666 !important;
}
</style>

View File

@ -2,16 +2,44 @@
<KlNavTab /> <KlNavTab />
<div class="mx-auto mt-[30px] box-border w-[1200px] border border-[#EEEEEE] rounded-[12px] border-solid bg-white px-[30px] py-[40px]"> <div class="mx-auto mt-[30px] box-border w-[1200px] border border-[#EEEEEE] rounded-[12px] border-solid bg-white px-[30px] py-[40px]">
<el-form ref="formRef" :model="form" label-width="110px" size="large"> <el-form ref="formRef" :model="form" label-width="110px" size="large">
<el-form-item label-width="110px" label="标题:" prop="title" :rules="{ required: true, message: '请输入标题', trigger: ['blur', 'change'] }"> <el-form-item
label-width="110px"
label="标题:"
prop="title"
:rules="[
{ required: true, message: '请输入标题', trigger: ['blur', 'change'] },
{
validator: (rule, value, callback) => {
if (value.length >= 10 && value.length <= 30) {
if (value.indexOf('破解') !== -1) {
callback(new Error('标题不能包含破解'))
} else {
callback()
}
} else {
callback(new Error('标题长度必须在10-30个字符之间'))
}
},
trigger: ['blur', 'change'],
},
]"
>
<el-input v-model="form.title" placeholder="请输入标题" class="w-[361px]!" maxlength="128"></el-input> <el-input v-model="form.title" placeholder="请输入标题" class="w-[361px]!" maxlength="128"></el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="分类:" prop="projectType" :rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }"> <el-form-item label-width="110px" label="软件分类:" prop="categoryId" :rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }">
<el-select v-model="form.projectType" placeholder="请选择分类" class="w-[361px]!" multiple> <!-- <el-select v-model="form.categoryId" placeholder="请选择软件分类" class="w-[361px]!" multiple>
<el-option v-for="(item, index) in projectTypeList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in projectTypeList" :key="index" :label="item.name" :value="item.id" />
</el-select> </el-select> -->
<el-cascader v-model="form.categoryId" class="w-[361px]!" :options="projectTypeList" :props="cascaderProps" clearable collapse-tags />
</el-form-item>
<el-form-item label-width="110px" label="分类:" prop="sourceType" :rules="{ required: true, message: '请选择', trigger: ['blur', 'change'] }">
<el-radio-group v-model="form.sourceType">
<el-radio :label="0">原创开发</el-radio>
<el-radio :label="1">转载分享</el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="标签:" prop="labels" :rules="{ required: true, message: '请选择标签', trigger: ['blur', 'change'] }"> <el-form-item label-width="110px" label="标签:" prop="labels" :rules="{ required: false, message: '请选择标签', trigger: ['blur', 'change'] }">
<el-select <el-select
v-model="form.labels" v-model="form.labels"
:remote-method="remoteMethod" :remote-method="remoteMethod"
@ -26,7 +54,14 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="金币:" prop="points" :rules="{ required: true, message: '请输入金币', trigger: ['blur', 'change'] }"> <el-form-item label-width="110px" label="金币:" prop="points" :rules="{ required: true, message: '请输入金币', trigger: ['blur', 'change'] }">
<el-input-number v-model="form.points" :controls="false" :precision="0" :min="0" placeholder="请输入金币" class="w-[361px]! text-left!"></el-input-number> <el-input-number
v-model="form.points"
:controls="false"
:precision="0"
:min="0"
placeholder="金币设置分销为0-15,设置0金币为专属资源可直接获利2-15金币"
class="w-[361px]! text-left!"
></el-input-number>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -50,7 +85,7 @@
</KlUploader> </KlUploader>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="上传附件" prop="files" :rules="{ required: true, message: '请上传附件', trigger: ['blur', 'change'] }"> <el-form-item label-width="110px" label="上传工具" prop="files" :rules="{ required: true, message: '请上传工具', trigger: ['blur', 'change'] }">
<KlUploader v-model:file-list="form.files" tips="请将系列文件分别压缩后上传,支持批量上传"> </KlUploader> <KlUploader v-model:file-list="form.files" tips="请将系列文件分别压缩后上传,支持批量上传"> </KlUploader>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -62,8 +97,8 @@
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
console.log(rule) console.log(rule)
if (value.length < 70) { if (value.length < 30) {
callback(new Error('输入内容不能少于 70 字')) callback(new Error('输入内容不能少于 30 字'))
} else { } else {
callback() callback()
} }
@ -72,13 +107,21 @@
}, },
]" ]"
> >
<el-input v-model="form.description" type="textarea" :rows="6" placeholder="请输入描述" class="w-[361px]!" minlength="70" show-word-limit></el-input> <el-input
v-model="form.description"
type="textarea"
:rows="6"
placeholder="限制30~200字介绍工具使用用途场景等"
class="w-[361px]!"
maxlength="200"
show-word-limit
></el-input>
</el-form-item> </el-form-item>
<!-- 添加预览和保存按钮 --> <!-- 添加预览和保存按钮 -->
<el-form-item label-width="110px" label=" "> <el-form-item label-width="110px" label=" ">
<div class="flex justify-start"> <div class="flex justify-start">
<!-- <el-button @click="save" :loading="saveLoading" type="primary" class="btn">预览</el-button> --> <!-- <el-button @click="save" :loading="saveLoading" type="primary" class="btn">预览</el-button> -->
<el-button :loading="saveLoading" type="primary" class="btn" @click="save">保存</el-button> <el-button :loading="saveLoading" type="primary" class="btn" @click="save">发布工具</el-button>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -102,8 +145,12 @@
coverImages: [], coverImages: [],
files: [], files: [],
description: '', description: '',
categoryId: 0,
sourceType: 0,
}) })
const cascaderProps = { multiple: false, label: 'name', value: 'id', emitPath: false }
const loading = ref(false) const loading = ref(false)
/** 获取标签 */ /** 获取标签 */
const labelsList = ref<any>([]) const labelsList = ref<any>([])
@ -140,7 +187,7 @@
/** 获取分类下拉框 */ /** 获取分类下拉框 */
const getParent = () => { const getParent = () => {
parent({ parent({
type: 1, type: 3,
parentId: 0, parentId: 0,
}).then((res) => { }).then((res) => {
projectTypeList.value = res.data projectTypeList.value = res.data

View File

@ -2,27 +2,30 @@
<KlNavTab active="工具箱" /> <KlNavTab active="工具箱" />
<!-- 搜索 --> <!-- 搜索 -->
<KlSearch @search="search"></KlSearch> <KlSearch @search="search"></KlSearch>
<div v-loading="loading" class="ma-auto mt-[20px] w-[1440px] flex justify-center gap-[60px]"> <div v-loading="loading" class="ma-auto mt-[20px] w-[1440px] flex justify-between">
<div class="left w-[821px]"> <div class="left w-[1000px]">
<img src="~/assets/images/banner2.png" alt="" srcset="" class="h-[284px] w-[100%]" /> <KlWallpaperCategory v-model="pageReq.categoryId" />
<div <KlTabBar v-model="pageReq.sourceType" :data="tabBar" class="mt-[20px]" />
class="box-border border border-t-[0px] border-t-[0px] border-[#EEEEEE] rounded-[12px] border-solid border-t-none bg-[#FFFFFF] px-[28px] py-[17px]" <div class="mt-[4px] box-border border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[28px] py-[17px]" v-loading="loading">
style="border-top-left-radius: 0px; border-top-right-radius: 0px" <div
> @click="handleClick(item)"
<div v-for="item in pageRes?.list" :key="item.id" class="mt-[20px] flex border-b-[1px] border-b-[#eee] border-b-solid pb-[20px]"> v-for="item in pageRes?.list"
:key="item.id"
class="mt-[20px] flex border-b-[1px] border-b-[#eee] border-b-solid pb-[20px] cursor-pointer"
>
<div class="h-[142px] w-[200px] text-center"> <div class="h-[142px] w-[200px] text-center">
<el-image :src="item.iconUrl" alt="" srcset="" class="max-w-[100%] rd-[4px]" fit="cover" /> <el-image :src="item.iconUrl" alt="" srcset="" class="max-w-[100%] rd-[4px]" fit="cover" />
</div> </div>
<div class="ml-[25px] flex-1"> <div class="ml-[25px] flex-1">
<div class="text-[16px] text-[#333333] font-normal">{{ item.title }}</div> <div class="text-[15px] text-[#333333] font-normal">{{ item.title }}</div>
<div class="mt-[8px] text-[14px] text-[#999999] font-normal">{{ item.description }}</div> <div class="mt-[8px] text-[14px] text-[#999999] font-normal line-clamp-3" :title="item.description">{{ item.description }}</div>
<div class="mt-[10px] flex items-center justify-between"> <div class="mt-[10px] flex items-center justify-between">
<div class="flex items-center"> <div class="flex items-center">
<div class="flex items-center text-[14px] text-[#666666] font-normal"> <div class="flex items-center text-[14px] text-[#666666] font-normal">
<img src="~/assets/images/look.png" alt="" srcset="" class="mr-[4px] h-[17px] w-[23px]" />{{ item.previewPoint }} <img src="~/assets/images/look.png" alt="" srcset="" class="mr-[4px] h-[14px] w-[20px]" />{{ item.previewPoint }}
</div> </div>
<div class="ml-[26px] flex items-center text-[14px] text-[#666666] font-normal"> <div class="ml-[26px] flex items-center text-[14px] text-[#666666] font-normal">
<img src="~/assets/images/chat.png" alt="" srcset="" class="mr-[4px] h-[17px] w-[19px]" /> {{ item.commentsPoint }} <img src="~/assets/images/chat.png" alt="" srcset="" class="mr-[4px] h-[14px] w-[16px]" /> {{ item.commentsPoint }}
</div> </div>
<div class="ml-[20px]"> <div class="ml-[20px]">
<div v-for="(v, index) in item.labels" :key="index" class="mr-[10px] inline-block text-[14px] text-[#1A65FF] font-normal">#{{ v }}</div> <div v-for="(v, index) in item.labels" :key="index" class="mr-[10px] inline-block text-[14px] text-[#1A65FF] font-normal">#{{ v }}</div>
@ -39,7 +42,7 @@
</div> </div>
<el-pagination <el-pagination
v-if="pageRes?.list.length" v-if="pageRes?.list.length"
v-model:current-page="pageReq.pageNum" v-model:current-page="pageReq.pageNo"
:page-size="pageReq.pageSize" :page-size="pageReq.pageSize"
layout="total, prev, pager, next" layout="total, prev, pager, next"
:total="pageRes?.total" :total="pageRes?.total"
@ -49,44 +52,14 @@
/> />
</div> </div>
</div> </div>
<div class="right w-[398px]"> <div class="right w-[400px]">
<div class="box-border border border-[#EEEEEE] rounded-[10px] border-solid bg-[#FFFFFF] pa-[20px]"> <div class="box-border border border-[#EEEEEE] rounded-[10px] border-solid bg-[#FFFFFF] pa-[16px]">
<div class="flex items-center text-[16px] text-[#333333] font-normal"> <div class="flex items-center text-[14px] text-[#333333] font-normal">
<div class="mr-[14px] h-[24px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div> <div class="mr-[14px] h-[16px] w-[4px] rounded-[1px] bg-[#1A65FF]"></div>
热门排行 热门排行
</div> </div>
<div v-for="item in recommendList" :key="item.id" class="mt-[20px] text-[14px] text-[#666] font-normal">{{ item.title }}</div> <div v-for="item in recommendList" :key="item.id" class="mt-[20px] text-[14px] text-[#666] font-normal">{{ item.title }}</div>
</div> </div>
<!-- -->
<!-- <div class="mt-20px box-border w-398px border border-[#EEEEEE] rounded-10px border-solid bg-[#FFFFFF] pa-20px">
<div class="mb-20px flex items-center text-16px text-[#333333] font-normal">
<div class="mr-14px h-24px w-4px rounded-1px bg-[#1A65FF]"></div>
标签列表
</div>
<div class="flex flex-wrap">
<div
v-for="item in 10"
:key="item"
class="mb-19px mr-26px box-border border border-[#D7D7D7] rounded-4px border-solid px-8px py-12px text-16px text-[#1A65FF] font-normal"
># 标签名称1</div
>
</div>
</div> -->
<!-- -->
<!-- <div class="mt-20px box-border w-398px border border-[#EEEEEE] rounded-10px border-solid bg-[#FFFFFF] pa-20px">
<div class="mb-20px flex items-center text-16px text-[#333333] font-normal">
<div class="mr-14px h-24px w-4px rounded-1px bg-[#1A65FF]"></div>
猜你喜欢
</div>
<div
v-for="item in 4"
:key="item"
class="mt-16px flex items-center border-b-1px border-b-[#eee] border-b-solid pb-16px text-16px text-[#333333] font-normal"
>
<img src="~/assets/images/aucad.png" alt="" srcset="" class="h-68px w-110px" />
<div class="ml-20px text-16px text-[#333333] font-normal">Stable Diffusion 商业变现与 绘画大模型多场景实战</div>
</div>
</div> -->
</div> </div>
</div> </div>
</template> </template>
@ -94,69 +67,93 @@
<script setup lang="ts"> <script setup lang="ts">
import KlNavTab from '~/components/kl-nav-tab/index.vue' import KlNavTab from '~/components/kl-nav-tab/index.vue'
import { page } from '~/api/toolbox/index.js' import { page } from '~/api/toolbox/index.js'
import type { TpageReq, TpageRes } from '~/api/toolbox/types' import { reactive, ref, watch } from 'vue'
import { reactive, ref } from 'vue'
import KlSearch from '~/pages/toolbox/components/search.vue' import KlSearch from '~/pages/toolbox/components/search.vue'
import { getRelationRecommend } from '~/api/drawe-detail/index' import { getRelationRecommend } from '~/api/drawe-detail/index'
import type { ProjectDrawPageRespVO } from '~/api/drawe-detail/types' import type { ProjectDrawPageRespVO } from '~/api/drawe-detail/types'
import { parent } from '~/api/upnew/index'
import emptyImg from '~/assets/images/empty.png' import emptyImg from '~/assets/images/empty.png'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import KlWallpaperCategory from '~/components/toolbox-components/kl-wallpaper-category.vue'
const pageReq = reactive<TpageReq>({ const cascaderProps = { multiple: false, label: 'name', value: 'id', emitPath: false }
pageNum: 1,
const pageReq = reactive({
pageNo: 1,
pageSize: 10, pageSize: 10,
title: '', title: '',
categoryId: '-1',
sourceType: -1,
}) })
// const pageRes = ref<TpageRes>({ const tabBar = ref([
// list: [], {
// total: 0, label: '推荐工具',
// }) value: -1,
},
{
label: '原创开发',
value: 0,
},
{
label: '转载分享',
value: 1,
},
])
const recommedComputed = computed(() => {
if (pageReq.sourceType === -1) {
return true
}
return false
})
const loading = ref(false)
const { data: pageRes, refresh: getPage } = await useAsyncData( const { data: pageRes, refresh: getPage } = await useAsyncData(
`draw-page-toobox-list`, `draw-page-toobox-list`,
async () => { async () => {
const res = await page(pageReq) loading.value = true
return res.data const res = await page({
...pageReq,
recommend: recommedComputed,
sourceType: pageReq.sourceType === -1 ? undefined : pageReq.sourceType,
categoryId: pageReq.categoryId === '-1' ? undefined : pageReq.categoryId,
})
loading.value = false
if (res.code === 0) {
return res.data
}
return {
list: [],
total: 0,
}
}, },
{ {
immediate: true, immediate: true,
} }
) )
const loading = ref(false)
// const getPage = () => {
// loading.value = true
// page(pageReq)
// .then((res) => {
// if (res.code === 0) {
// pageRes.value = res.data
// }
// })
// .finally(() => {
// loading.value = false
// })
// }
// getPage()
const handleCurrentChange = (page: number) => { const handleCurrentChange = (page: number) => {
pageReq.pageNum = page pageReq.pageNo = page
getPage() getPage()
} }
const handleSizeChange = (size: number) => { const handleSizeChange = (size: number) => {
pageReq.pageSize = size pageReq.pageSize = size
pageReq.pageNum = 1 pageReq.pageNo = 1
getPage() getPage()
} }
const search = (val?: string) => { const search = (val?: string) => {
pageReq.pageNum = 1 pageReq.pageNo = 1
pageReq.title = val || '' pageReq.title = val || ''
getPage() getPage()
} }
const handleClick = (item: ProjectDrawPageRespVO) => {
navigateTo(`/toolbox-detail/${item.id}`)
}
const { data: recommendList } = await useAsyncData(`draw-recommend-list-getRelationRecommend`, async () => { const { data: recommendList } = await useAsyncData(`draw-recommend-list-getRelationRecommend`, async () => {
const res = await getRelationRecommend({ const res = await getRelationRecommend({
type: 4, type: 4,
@ -164,17 +161,15 @@
return res.data return res.data
}) })
// 猜你喜欢 const { data: projectTypeList } = await useAsyncData(`project-type-list`, async () => {
// const recommendList = ref<ProjectDrawPageRespVO[]>([]) // 猜你喜欢数据 const res = await parent({
// const getRelationRecommendList = () => { type: 3,
// getRelationRecommend({ parentId: 0,
// type: 4, })
// }).then((res) => { return res.data
// if (res.code === 0) { })
// console.log(res.data)
// recommendList.value = res.data watch([() => pageReq.sourceType, () => pageReq.categoryId], (val) => {
// } getPage()
// }) })
// }
// getRelationRecommendList()
</script> </script>

View File

@ -17,11 +17,11 @@
label="标题:" label="标题:"
:prop="`${props.vaildRules}.title`" :prop="`${props.vaildRules}.title`"
:rules="[ :rules="[
{ required: true, message: '20-50 字符,结构可用分类关键词+作品名/资源价值版本/使用场景', trigger: ['blur', 'change'] }, { required: true, message: '10-25 字符,结构可用分类关键词+作品名/资源价值版本/使用场景', trigger: ['blur', 'change'] },
{ {
validator: (rule: any, value: any, callback: any) => { validator: (rule: any, value: any, callback: any) => {
if (value && value.length < 20) { if (value && value.length < 10) {
callback(new Error('20-50 字符,结构可用分类关键词+作品名/资源价值版本/使用场景')) callback(new Error('10-25 字符,结构可用分类关键词+作品名/资源价值版本/使用场景'))
} }
callback() callback()
}, },
@ -29,7 +29,7 @@
}, },
]" ]"
> >
<el-input v-model="form.title" placeholder="20-50 字符,结构可用分类关键词+作品名/资源价值版本/使用场景" minlength="20" maxlength="50"></el-input> <el-input v-model="form.title" placeholder="10-25 字符,结构可用分类关键词+作品名/资源价值版本/使用场景" minlength="20" maxlength="50"></el-input>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label-width="110px" label-width="110px"
@ -131,7 +131,7 @@
</div> </div>
</KlUploader> </KlUploader>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="上传附件:"> <el-form-item label-width="110px" label="上传附件:" :prop="`${props.vaildRules}.otherFiles`" :rules="{ required: true, message: '请上传附件', trigger: ['blur', 'change'] }">
<KlUploader v-model:file-list="form.otherFiles" tips="请将系列文件分别压缩后上传,支持批量上传"> </KlUploader> <KlUploader v-model:file-list="form.otherFiles" tips="请将系列文件分别压缩后上传,支持批量上传"> </KlUploader>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -139,12 +139,12 @@
label="作品描述:" label="作品描述:"
:prop="`${props.vaildRules}.description`" :prop="`${props.vaildRules}.description`"
:rules="[ :rules="[
{ required: true, message: '简介字数限制60-150 字符,需包含用途、文件介绍、适用场景等', trigger: ['blur', 'change'] }, { required: true, message: '简介字数限制30-75 字符,需包含用途、文件介绍、适用场景等', trigger: ['blur', 'change'] },
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
console.log(rule) console.log(rule)
if (value.length < 60) { if (value.length < 30) {
callback(new Error('简介字数限制60-150 字符,需包含用途、文件介绍、适用场景等')) callback(new Error('简介字数限制30-75 字符,需包含用途、文件介绍、适用场景等'))
} else { } else {
callback() callback()
} }
@ -153,7 +153,7 @@
}, },
]" ]"
> >
<el-input v-model="form.description" type="textarea" :rows="6" placeholder="简介字数限制60-150 字符,需包含用途、文件介绍、适用场景等" minlength="60" maxlength="150" show-word-limit></el-input> <el-input v-model="form.description" type="textarea" :rows="6" placeholder="简介字数限制30-75 字符,需包含用途、文件介绍、适用场景等" minlength="60" maxlength="150" show-word-limit></el-input>
</el-form-item> </el-form-item>
</div> </div>
</template> </template>

View File

@ -55,7 +55,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, ref } from 'vue' import { nextTick, ref, watchEffect } from 'vue'
import type { TcreateReq } from '~/api/upnew/types' import type { TcreateReq } from '~/api/upnew/types'
import { tree } from '~/api/common/index' import { tree } from '~/api/common/index'
import { DrawsEnmu } from '../util' import { DrawsEnmu } from '../util'
@ -123,6 +123,12 @@
} }
} }
watchEffect(() => {
if (form.value.isDomestic === 0) {
getAdress('province', form.value.isDomestic)
}
})
defineExpose({ defineExpose({
handleTypeChange, handleTypeChange,
}) })

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="ml-[23px] box-border h-[330px] w-[400px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]"> <div class="ml-[23px] box-border h-[400px] w-[400px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]">
<!-- <div class="flex items-center"> <!-- <div class="flex items-center">
<img src="~/assets/images/preview.png" alt="" srcset="" width="16px" height="19px" /><span class="ml-[7px] text-[18px] text-[#333333] font-normal"> <img src="~/assets/images/preview.png" alt="" srcset="" width="16px" height="19px" /><span class="ml-[7px] text-[18px] text-[#333333] font-normal">
预览 预览
@ -15,8 +15,8 @@
<span class="ml-[7px] text-[16px] text-[#666] font-normal">tips遇到上传问题可以咨询 </span> <span class="ml-[7px] text-[16px] text-[#666] font-normal">tips遇到上传问题可以咨询 </span>
</div> </div>
<div class="mt-[20px] text-center"> <div class="mt-[20px] text-center">
<qrcode-vue :value="wechatData" :size="200" level="H" class="mt-[10px]" /> <!-- <qrcode-vue :value="wechatData" :size="200" level="H" class="mt-[10px]" /> -->
<!-- <el-image src="https://picsum.photos/290/290?_t" alt="" srcset="" class="h-[290px] w-[290px]" /> --> <el-image :src="wechatData" alt="" srcset="" class="h-[290px] w-[290px]" />
</div> </div>
<!-- <div class="mt-[30px] text-center text-[16px] text-[#333333] font-normal"> <!-- <div class="mt-[30px] text-center text-[16px] text-[#333333] font-normal">
<div>TEL13315189735 </div> <div>TEL13315189735 </div>
@ -26,7 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import QrcodeVue from 'qrcode.vue' // import QrcodeVue from 'qrcode.vue'
import { getWechat } from '~/api/upnew/index' import { getWechat } from '~/api/upnew/index'
const previewUrl = defineModel<string>('previewUrl', { const previewUrl = defineModel<string>('previewUrl', {
required: true, required: true,

View File

@ -4,7 +4,7 @@
<!-- 发布图纸 --> <!-- 发布图纸 -->
<div class="ma-auto mt-[30px] w-[1440px] flex"> <div class="ma-auto mt-[30px] w-[1440px] flex">
<div class="w-[1016px]"> <div class="w-[1016px]">
<el-form ref="formRef" :model="form" label-width="120px"> <el-form ref="formRef" :model="form" label-width="120px" :disabled="type === 'preview'">
<!-- 图纸分类 --> <!-- 图纸分类 -->
<DrawType ref="drawTypeRef" v-model="form" /> <DrawType ref="drawTypeRef" v-model="form" />
<div class="mt-[24px] box-border border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]"> <div class="mt-[24px] box-border border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]">
@ -13,7 +13,7 @@
<DrawForm v-if="form.draws[index]" v-model="form.draws[index]" :vaild-rules="'draws.' + index" :form-ref="formRef" @preview="handlePreview" /> <DrawForm v-if="form.draws[index]" v-model="form.draws[index]" :vaild-rules="'draws.' + index" :form-ref="formRef" @preview="handlePreview" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<el-form-item label-width="110px"> <el-form-item label-width="110px" v-if="type !== 'preview'">
<!-- <el-button class="w-121px h-37px!" :loading="loading" @click="handleSubmit">预览</el-button> --> <!-- <el-button class="w-121px h-37px!" :loading="loading" @click="handleSubmit">预览</el-button> -->
<el-button type="primary" class="w-[121px] h-[37px]!" :loading="loading" @click="handleSubmit">发布</el-button> <el-button type="primary" class="w-[121px] h-[37px]!" :loading="loading" @click="handleSubmit">发布</el-button>
</el-form-item> </el-form-item>
@ -32,8 +32,23 @@
import { reactive, ref, onMounted, computed } from 'vue' import { reactive, ref, onMounted, computed } from 'vue'
import type { TcreateReq } from '~/api/upnew/types' import type { TcreateReq } from '~/api/upnew/types'
import { create } from '~/api/upnew/index' import { create, view, edit } from '~/api/upnew/index'
const route = useRoute() // 导入路由实例,用于跳转页面
const router = useRouter() // 导入路由实例,用于跳转页面 const router = useRouter() // 导入路由实例,用于跳转页面
const id = computed(() => {
return route.query.id as string
})
const projectId = computed(() => {
return route.query.projectId as string
})
const type = computed(() => {
return route.query.type || 'add'
})
const drawType = computed(() => {
return route.query.drawType || 1
})
const form = reactive<TcreateReq>({ const form = reactive<TcreateReq>({
activeName: 1, // 标签 activeName: 1, // 标签
@ -84,28 +99,30 @@
const loading = ref(false) const loading = ref(false)
const formRef = ref() const formRef = ref()
const handleSubmit = () => { const handleSubmit = () => {
formRef.value.validate((valid: boolean, val: any) => { formRef.value.validate(async (valid: boolean, val: any) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
create(form) try {
.then((res) => { const res = type.value === 'add' ? await create(form) : await edit(form)
const { code } = res if (res.code === 0) {
if (code === 0) { // 弹窗提示
// 弹窗提示 ElMessage.success('操作成功')
ElMessage.success('操作成功') if (type.value !== 'add') {
// 跳转页面 router.back()
if (form.type === 1) { return
navigateTo('/drawe')
} else if (form.type === 2) {
navigateTo('/text')
} else if (form.type === 3) {
navigateTo('/model')
}
} }
}) // 跳转页面
.finally(() => { if (form.type === 1) {
loading.value = false navigateTo('/drawe')
}) } else if (form.type === 2) {
navigateTo('/text')
} else if (form.type === 3) {
navigateTo('/model')
}
}
} finally {
loading.value = false
}
} else { } else {
console.log('error submit!') console.log('error submit!')
// 弹窗提示 // 弹窗提示
@ -123,13 +140,49 @@
// previewForm.name = val.name // previewForm.name = val.name
} }
/** 组装回显的数据 */
const getDetail = () => {
view({ id: id.value, projectId: projectId.value }).then((res) => {
const { code, data } = res
if (code === 0) {
form.id = data.id
form.isDomestic = data.isDomestic
form.province = data.province
form.city = data.city
form.county = data.county
form.activeName = form.type = data.draws[0].type
form.draws = data.draws.map((c) => {
return {
...c,
coverImages: c.coverImages.map((d) => {
return {
...d,
name: d.title,
}
}),
otherFiles: c.otherFiles.map((d) => {
return {
...d,
name: d.title,
}
}),
}
})
}
})
}
// 图纸类型 // 图纸类型
const drawTypeRef = ref<InstanceType<typeof DrawType>>() const drawTypeRef = ref<InstanceType<typeof DrawType>>()
onMounted(() => { onMounted(() => {
// 初始化图纸类型 // 初始化图纸类型
drawTypeRef.value?.handleTypeChange(1) drawTypeRef.value?.handleTypeChange(Number(drawType.value))
// 初始化图纸类型 // 初始化图纸类型
form.type = 1 form.type = Number(drawType.value)
if (type.value !== 'add') {
getDetail()
}
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

11
plugins/error-handler.ts Normal file
View File

@ -0,0 +1,11 @@
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
// 处理错误,例如发送报告到服务
console.log(error)
}
// 也可以这样做
// nuxtApp.hook('vue:error', (error, instance, info) => {
// // 处理错误,例如发送报告到服务
// })
})

View File

@ -28,6 +28,8 @@ export default defineStore('useUserStore', {
this.userName = userName this.userName = userName
}, },
logout() { logout() {
const token = useCookie<string | undefined>('token')
token.value = ''
refreshToken.removeToken() refreshToken.removeToken()
localStorage.removeItem('tuxixi-store') localStorage.removeItem('tuxixi-store')
if (self === top) { if (self === top) {
@ -97,6 +99,39 @@ export default defineStore('useUserStore', {
console.error('getToken error:', error) console.error('getToken error:', error)
} }
}, },
async getTokenV2(row: any) {
const app = useNuxtApp()
try {
const res = await socialLoginByCode({
openId: row.openId,
sceneStr: row.sceneStr,
type: 32
})
const { code, data } = res
if (code === 0) {
// 打开登录界面
if (!data.accessToken) {
ElMessage.error('因你未绑定手机号,请先绑定手机号')
app.$openLogin('verify', row.code, row.type, row.state)
} else {
refreshToken.setToken(data.accessToken, data.refreshToken)
refreshToken.setUserId(data.userId.toString())
// refreshToken.setUserName(loginForm.mobile)
this.setToken(data.accessToken)
this.setUserId(data.userId.toString())
// userStore.setUserName(loginForm.mobile)
this.setRefreshToken(data.refreshToken)
// 获取信息
await this.getUserInfo()
}
} else {
console.error('获取token失败:', res.msg)
}
} catch (error) {
console.error('getToken error:', error)
}
},
}, },
persist: import.meta.client && { persist: import.meta.client && {
key: 'tuxixi-store', key: 'tuxixi-store',

View File

@ -13,19 +13,17 @@ export const generateRandomString = (length: number) => {
// QQ登录 // QQ登录
export const handleLoginQQ = () => { export const handleLoginQQ = () => {
const appId = QQ_APP_ID // APP ID const redirectUri = encodeURIComponent('https://tuxixi.net?type=35') // 回调地址
const redirectUri = encodeURIComponent('https://tuxixi.net/index?type=35') // 回调地址
const state = generateRandomString(16) // 生成随机state const state = generateRandomString(16) // 生成随机state
// 存储state用于后续验证 // 存储state用于后续验证
localStorage.setItem('qq_login_state', state) localStorage.setItem('qq_login_state', state)
window.location.href = `https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=${appId}&redirect_uri=${redirectUri}&state=${state}` window.location.href = `https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=${QQ_APP_ID}&redirect_uri=${redirectUri}&state=${state}`
} }
export const handleLoginWechat = () => { export const handleLoginWechat = () => {
const appId = WECHAT_APP_ID // APP ID
const redirectUri = encodeURIComponent('https://tuxixi.net?type=32') // 回调地址 const redirectUri = encodeURIComponent('https://tuxixi.net?type=32') // 回调地址
const state = generateRandomString(16) // 生成随机state const state = generateRandomString(16) // 生成随机state
// 存储state用于后续验证 // 存储state用于后续验证
localStorage.setItem('wechat_login_state', state) localStorage.setItem('wechat_login_state', state)
window.location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_login&state=${state}` window.location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${WECHAT_APP_ID}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_login&state=${state}`
} }