From a318b296f4411915b4adb1f4e45730f98cdcf1f2 Mon Sep 17 00:00:00 2001 From: eight <641137800@qq.com> Date: 星期五, 30 八月 2024 11:20:29 +0800 Subject: [PATCH] remove 无关模块 --- /dev/null | 68 ---------------------------------- 1 files changed, 0 insertions(+), 68 deletions(-) diff --git a/src/api/ai/chat/conversation/index.ts b/src/api/ai/chat/conversation/index.ts deleted file mode 100644 index 6ce4482..0000000 --- a/src/api/ai/chat/conversation/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -import request from '@/config/axios' - -// AI 鑱婂ぉ瀵硅瘽 VO -export interface ChatConversationVO { - id: number // ID 缂栧彿 - userId: number // 鐢ㄦ埛缂栧彿 - title: string // 瀵硅瘽鏍囬 - pinned: boolean // 鏄惁缃《 - roleId: number // 瑙掕壊缂栧彿 - modelId: number // 妯″瀷缂栧彿 - model: string // 妯″瀷鏍囧織 - temperature: number // 娓╁害鍙傛暟 - maxTokens: number // 鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺 - maxContexts: number // 涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺 - createTime?: Date // 鍒涘缓鏃堕棿 - // 棰濆瀛楁 - systemMessage?: string // 瑙掕壊璁惧畾 - modelName?: string // 妯″瀷鍚嶅瓧 - roleAvatar?: string // 瑙掕壊澶村儚 - modelMaxTokens?: string // 妯″瀷鐨勫崟鏉″洖澶嶇殑鏈�澶� Token 鏁伴噺 - modelMaxContexts?: string // 妯″瀷鐨勪笂涓嬫枃鐨勬渶澶� Message 鏁伴噺 -} - -// AI 鑱婂ぉ瀵硅瘽 API -export const ChatConversationApi = { - // 鑾峰緱銆愭垜鐨勩�戣亰澶╁璇� - getChatConversationMy: async (id: number) => { - return await request.get({ url: `/ai/chat/conversation/get-my?id=${id}` }) - }, - - // 鏂板銆愭垜鐨勩�戣亰澶╁璇� - createChatConversationMy: async (data?: ChatConversationVO) => { - return await request.post({ url: `/ai/chat/conversation/create-my`, data }) - }, - - // 鏇存柊銆愭垜鐨勩�戣亰澶╁璇� - updateChatConversationMy: async (data: ChatConversationVO) => { - return await request.put({ url: `/ai/chat/conversation/update-my`, data }) - }, - - // 鍒犻櫎銆愭垜鐨勩�戣亰澶╁璇� - deleteChatConversationMy: async (id: string) => { - return await request.delete({ url: `/ai/chat/conversation/delete-my?id=${id}` }) - }, - - // 鍒犻櫎銆愭垜鐨勩�戞墍鏈夊璇濓紝缃《闄ゅ - deleteChatConversationMyByUnpinned: async () => { - return await request.delete({ url: `/ai/chat/conversation/delete-by-unpinned` }) - }, - - // 鑾峰緱銆愭垜鐨勩�戣亰澶╁璇濆垪琛� - getChatConversationMyList: async () => { - return await request.get({ url: `/ai/chat/conversation/my-list` }) - }, - - // 鑾峰緱瀵硅瘽鍒嗛〉 - getChatConversationPage: async (params: any) => { - return await request.get({ url: `/ai/chat/conversation/page`, params }) - }, - - // 绠$悊鍛樺垹闄ゆ秷鎭� - deleteChatConversationByAdmin: async (id: number) => { - return await request.delete({ url: `/ai/chat/conversation/delete-by-admin?id=${id}` }) - } -} diff --git a/src/api/ai/chat/message/index.ts b/src/api/ai/chat/message/index.ts deleted file mode 100644 index ef1196a..0000000 --- a/src/api/ai/chat/message/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -import request from '@/config/axios' -import { fetchEventSource } from '@microsoft/fetch-event-source' -import { getAccessToken } from '@/utils/auth' -import { config } from '@/config/axios/config' - -// 鑱婂ぉVO -export interface ChatMessageVO { - id: number // 缂栧彿 - conversationId: number // 瀵硅瘽缂栧彿 - type: string // 娑堟伅绫诲瀷 - userId: string // 鐢ㄦ埛缂栧彿 - roleId: string // 瑙掕壊缂栧彿 - model: number // 妯″瀷鏍囧織 - modelId: number // 妯″瀷缂栧彿 - content: string // 鑱婂ぉ鍐呭 - tokens: number // 娑堣�� Token 鏁伴噺 - createTime: Date // 鍒涘缓鏃堕棿 - roleAvatar: string // 瑙掕壊澶村儚 - userAvatar: string // 鍒涘缓鏃堕棿 -} - -// AI chat 鑱婂ぉ -export const ChatMessageApi = { - // 娑堟伅鍒楄〃 - getChatMessageListByConversationId: async (conversationId: number | null) => { - return await request.get({ - url: `/ai/chat/message/list-by-conversation-id?conversationId=${conversationId}` - }) - }, - - // 鍙戦�� Stream 娑堟伅 - // 涓轰粈涔堜笉鐢� axios 鍛紵鍥犱负瀹冧笉鏀寔 SSE 璋冪敤 - sendChatMessageStream: async ( - conversationId: number, - content: string, - ctrl, - enableContext: boolean, - onMessage, - onError, - onClose - ) => { - const token = getAccessToken() - return fetchEventSource(`${config.base_url}/ai/chat/message/send-stream`, { - method: 'post', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - }, - openWhenHidden: true, - body: JSON.stringify({ - conversationId, - content, - useContext: enableContext - }), - onmessage: onMessage, - onerror: onError, - onclose: onClose, - signal: ctrl.signal - }) - }, - - // 鍒犻櫎娑堟伅 - deleteChatMessage: async (id: string) => { - return await request.delete({ url: `/ai/chat/message/delete?id=${id}` }) - }, - - // 鍒犻櫎鎸囧畾瀵硅瘽鐨勬秷鎭� - deleteByConversationId: async (conversationId: number) => { - return await request.delete({ - url: `/ai/chat/message/delete-by-conversation-id?conversationId=${conversationId}` - }) - }, - - // 鑾峰緱娑堟伅鍒嗛〉 - getChatMessagePage: async (params: any) => { - return await request.get({ url: '/ai/chat/message/page', params }) - }, - - // 绠$悊鍛樺垹闄ゆ秷鎭� - deleteChatMessageByAdmin: async (id: number) => { - return await request.delete({ url: `/ai/chat/message/delete-by-admin?id=${id}` }) - } -} diff --git a/src/api/ai/image/index.ts b/src/api/ai/image/index.ts deleted file mode 100644 index f1905ca..0000000 --- a/src/api/ai/image/index.ts +++ /dev/null @@ -1,107 +0,0 @@ -import request from '@/config/axios' - -// AI 缁樺浘 VO -export interface ImageVO { - id: number // 缂栧彿 - platform: string // 骞冲彴 - model: string // 妯″瀷 - prompt: string // 鎻愮ず璇� - width: number // 鍥剧墖瀹藉害 - height: number // 鍥剧墖楂樺害 - status: number // 鐘舵�� - publicStatus: boolean // 鍏紑鐘舵�� - picUrl: string // 浠诲姟鍦板潃 - errorMessage: string // 閿欒淇℃伅 - options: any // 閰嶇疆 Map<string, string> - taskId: number // 浠诲姟缂栧彿 - buttons: ImageMidjourneyButtonsVO[] // mj 鎿嶄綔鎸夐挳 - createTime: Date // 鍒涘缓鏃堕棿 - finishTime: Date // 瀹屾垚鏃堕棿 -} - -export interface ImageDrawReqVO { - platform: string // 骞冲彴 - prompt: string // 鎻愮ず璇� - model: string // 妯″瀷 - style: string // 鍥惧儚鐢熸垚鐨勯鏍� - width: string // 鍥剧墖瀹藉害 - height: string // 鍥剧墖楂樺害 - options: object // 缁樺埗鍙傛暟锛孧ap<String, String> -} - -export interface ImageMidjourneyImagineReqVO { - prompt: string // 鎻愮ず璇� - model: string // 妯″瀷 mj nijj - base64Array: string[] // size涓嶈兘涓虹┖ - width: string // 鍥剧墖瀹藉害 - height: string // 鍥剧墖楂樺害 - version: string // 鐗堟湰 -} - -export interface ImageMidjourneyActionVO { - id: number // 鍥剧墖缂栧彿 - customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 鍔ㄤ綔鏍囪瘑 -} - -export interface ImageMidjourneyButtonsVO { - customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 鍔ㄤ綔鏍囪瘑 - emoji: string // 鍥炬爣 emoji - label: string // Make Variations 鏂囨湰 - style: number // 鏍峰紡: 2锛圥rimary锛夈��3锛圙reen锛� -} - -// AI 鍥剧墖 API -export const ImageApi = { - // 鑾峰彇銆愭垜鐨勩�戠粯鍥惧垎椤� - getImagePageMy: async (params: PageParam) => { - return await request.get({ url: `/ai/image/my-page`, params }) - }, - // 鑾峰彇鍏紑鐨勭粯鍥捐褰� - getImagePagePublic: async (params) => { - return await request.get({ url: `/ai/image/public-page`, params }) - }, - // 鑾峰彇銆愭垜鐨勩�戠粯鍥捐褰� - getImageMy: async (id: number) => { - return await request.get({ url: `/ai/image/get-my?id=${id}` }) - }, - // 鑾峰彇銆愭垜鐨勩�戠粯鍥捐褰曞垪琛� - getImageListMyByIds: async (ids: number[]) => { - return await request.get({ url: `/ai/image/my-list-by-ids`, params: { ids: ids.join(',') } }) - }, - // 鐢熸垚鍥剧墖 - drawImage: async (data: ImageDrawReqVO) => { - return await request.post({ url: `/ai/image/draw`, data }) - }, - // 鍒犻櫎銆愭垜鐨勩�戠粯鐢昏褰� - deleteImageMy: async (id: number) => { - return await request.delete({ url: `/ai/image/delete-my?id=${id}` }) - }, - - // ================ midjourney 涓撳睘 ================ - - // 銆怣idjourney銆戠敓鎴愬浘鐗� - midjourneyImagine: async (data: ImageMidjourneyImagineReqVO) => { - return await request.post({ url: `/ai/image/midjourney/imagine`, data }) - }, - // 銆怣idjourney銆慉ction 鎿嶄綔锛堜簩娆$敓鎴愬浘鐗囷級 - midjourneyAction: async (data: ImageMidjourneyActionVO) => { - return await request.post({ url: `/ai/image/midjourney/action`, data }) - }, - - // ================ 缁樺浘绠$悊 ================ - - // 鏌ヨ缁樼敾鍒嗛〉 - getImagePage: async (params: any) => { - return await request.get({ url: `/ai/image/page`, params }) - }, - - // 鏇存柊缁樼敾鍙戝竷鐘舵�� - updateImage: async (data: any) => { - return await request.put({ url: '/ai/image/update-public-status', data }) - }, - - // 鍒犻櫎缁樼敾 - deleteImage: async (id: number) => { - return await request.delete({ url: `/ai/image/delete?id=` + id }) - } -} diff --git a/src/api/ai/model/apiKey/index.ts b/src/api/ai/model/apiKey/index.ts deleted file mode 100644 index ed94836..0000000 --- a/src/api/ai/model/apiKey/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -import request from '@/config/axios' - -// AI API 瀵嗛挜 VO -export interface ApiKeyVO { - id: number // 缂栧彿 - name: string // 鍚嶇О - apiKey: string // 瀵嗛挜 - platform: string // 骞冲彴 - url: string // 鑷畾涔� API 鍦板潃 - status: number // 鐘舵�� -} - -// AI API 瀵嗛挜 API -export const ApiKeyApi = { - // 鏌ヨ API 瀵嗛挜鍒嗛〉 - getApiKeyPage: async (params: any) => { - return await request.get({ url: `/ai/api-key/page`, params }) - }, - - // 鑾峰緱 API 瀵嗛挜鍒楄〃 - getApiKeySimpleList: async () => { - return await request.get({ url: `/ai/api-key/simple-list` }) - }, - - // 鏌ヨ API 瀵嗛挜璇︽儏 - getApiKey: async (id: number) => { - return await request.get({ url: `/ai/api-key/get?id=` + id }) - }, - - // 鏂板 API 瀵嗛挜 - createApiKey: async (data: ApiKeyVO) => { - return await request.post({ url: `/ai/api-key/create`, data }) - }, - - // 淇敼 API 瀵嗛挜 - updateApiKey: async (data: ApiKeyVO) => { - return await request.put({ url: `/ai/api-key/update`, data }) - }, - - // 鍒犻櫎 API 瀵嗛挜 - deleteApiKey: async (id: number) => { - return await request.delete({ url: `/ai/api-key/delete?id=` + id }) - } -} diff --git a/src/api/ai/model/chatModel/index.ts b/src/api/ai/model/chatModel/index.ts deleted file mode 100644 index c2ef4c8..0000000 --- a/src/api/ai/model/chatModel/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import request from '@/config/axios' - -// AI 鑱婂ぉ妯″瀷 VO -export interface ChatModelVO { - id: number // 缂栧彿 - keyId: number // API 绉橀挜缂栧彿 - name: string // 妯″瀷鍚嶅瓧 - model: string // 妯″瀷鏍囪瘑 - platform: string // 妯″瀷骞冲彴 - sort: number // 鎺掑簭 - status: number // 鐘舵�� - temperature: number // 娓╁害鍙傛暟 - maxTokens: number // 鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺 - maxContexts: number // 涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺 -} - -// AI 鑱婂ぉ妯″瀷 API -export const ChatModelApi = { - // 鏌ヨ鑱婂ぉ妯″瀷鍒嗛〉 - getChatModelPage: async (params: any) => { - return await request.get({ url: `/ai/chat-model/page`, params }) - }, - - // 鑾峰緱鑱婂ぉ妯″瀷鍒楄〃 - getChatModelSimpleList: async (status?: number) => { - return await request.get({ - url: `/ai/chat-model/simple-list`, - params: { - status - } - }) - }, - - // 鏌ヨ鑱婂ぉ妯″瀷璇︽儏 - getChatModel: async (id: number) => { - return await request.get({ url: `/ai/chat-model/get?id=` + id }) - }, - - // 鏂板鑱婂ぉ妯″瀷 - createChatModel: async (data: ChatModelVO) => { - return await request.post({ url: `/ai/chat-model/create`, data }) - }, - - // 淇敼鑱婂ぉ妯″瀷 - updateChatModel: async (data: ChatModelVO) => { - return await request.put({ url: `/ai/chat-model/update`, data }) - }, - - // 鍒犻櫎鑱婂ぉ妯″瀷 - deleteChatModel: async (id: number) => { - return await request.delete({ url: `/ai/chat-model/delete?id=` + id }) - } -} diff --git a/src/api/ai/model/chatRole/index.ts b/src/api/ai/model/chatRole/index.ts deleted file mode 100644 index a9fce13..0000000 --- a/src/api/ai/model/chatRole/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import request from '@/config/axios' - -// AI 鑱婂ぉ瑙掕壊 VO -export interface ChatRoleVO { - id: number // 瑙掕壊缂栧彿 - modelId: number // 妯″瀷缂栧彿 - name: string // 瑙掕壊鍚嶇О - avatar: string // 瑙掕壊澶村儚 - category: string // 瑙掕壊绫诲埆 - sort: number // 瑙掕壊鎺掑簭 - description: string // 瑙掕壊鎻忚堪 - systemMessage: string // 瑙掕壊璁惧畾 - welcomeMessage: string // 瑙掕壊璁惧畾 - publicStatus: boolean // 鏄惁鍏紑 - status: number // 鐘舵�� -} - -// AI 鑱婂ぉ瑙掕壊 鍒嗛〉璇锋眰 vo -export interface ChatRolePageReqVO { - name?: string // 瑙掕壊鍚嶇О - category?: string // 瑙掕壊绫诲埆 - publicStatus: boolean // 鏄惁鍏紑 - pageNo: number // 鏄惁鍏紑 - pageSize: number // 鏄惁鍏紑 -} - -// AI 鑱婂ぉ瑙掕壊 API -export const ChatRoleApi = { - // 鏌ヨ鑱婂ぉ瑙掕壊鍒嗛〉 - getChatRolePage: async (params: any) => { - return await request.get({ url: `/ai/chat-role/page`, params }) - }, - - // 鏌ヨ鑱婂ぉ瑙掕壊璇︽儏 - getChatRole: async (id: number) => { - return await request.get({ url: `/ai/chat-role/get?id=` + id }) - }, - - // 鏂板鑱婂ぉ瑙掕壊 - createChatRole: async (data: ChatRoleVO) => { - return await request.post({ url: `/ai/chat-role/create`, data }) - }, - - // 淇敼鑱婂ぉ瑙掕壊 - updateChatRole: async (data: ChatRoleVO) => { - return await request.put({ url: `/ai/chat-role/update`, data }) - }, - - // 鍒犻櫎鑱婂ぉ瑙掕壊 - deleteChatRole: async (id: number) => { - return await request.delete({ url: `/ai/chat-role/delete?id=` + id }) - }, - - // ======= chat 鑱婂ぉ - - // 鑾峰彇 my role - getMyPage: async (params: ChatRolePageReqVO) => { - return await request.get({ url: `/ai/chat-role/my-page`, params}) - }, - - // 鑾峰彇瑙掕壊鍒嗙被 - getCategoryList: async () => { - return await request.get({ url: `/ai/chat-role/category-list`}) - }, - - // 鍒涘缓瑙掕壊 - createMy: async (data: ChatRoleVO) => { - return await request.post({ url: `/ai/chat-role/create-my`, data}) - }, - - // 鏇存柊瑙掕壊 - updateMy: async (data: ChatRoleVO) => { - return await request.put({ url: `/ai/chat-role/update-my`, data}) - }, - - // 鍒犻櫎瑙掕壊 my - deleteMy: async (id: number) => { - return await request.delete({ url: `/ai/chat-role/delete-my?id=` + id }) - }, -} diff --git a/src/api/ai/music/index.ts b/src/api/ai/music/index.ts deleted file mode 100644 index 74b8526..0000000 --- a/src/api/ai/music/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import request from '@/config/axios' - -// AI 闊充箰 VO -export interface MusicVO { - id: number // 缂栧彿 - userId: number // 鐢ㄦ埛缂栧彿 - title: string // 闊充箰鍚嶇О - lyric: string // 姝岃瘝 - imageUrl: string // 鍥剧墖鍦板潃 - audioUrl: string // 闊抽鍦板潃 - videoUrl: string // 瑙嗛鍦板潃 - status: number // 闊充箰鐘舵�� - gptDescriptionPrompt: string // 鎻忚堪璇� - prompt: string // 鎻愮ず璇� - platform: string // 妯″瀷骞冲彴 - model: string // 妯″瀷 - generateMode: number // 鐢熸垚妯″紡 - tags: string // 闊充箰椋庢牸鏍囩 - duration: number // 闊充箰鏃堕暱 - publicStatus: boolean // 鏄惁鍙戝竷 - taskId: string // 浠诲姟id - errorMessage: string // 閿欒淇℃伅 -} - -// AI 闊充箰 API -export const MusicApi = { - // 鏌ヨ闊充箰鍒嗛〉 - getMusicPage: async (params: any) => { - return await request.get({ url: `/ai/music/page`, params }) - }, - - // 鏇存柊闊充箰 - updateMusic: async (data: any) => { - return await request.put({ url: '/ai/music/update', data }) - }, - - // 鍒犻櫎闊充箰 - deleteMusic: async (id: number) => { - return await request.delete({ url: `/ai/music/delete?id=` + id }) - } -} diff --git a/src/api/ai/write/index.ts b/src/api/ai/write/index.ts deleted file mode 100644 index 013f998..0000000 --- a/src/api/ai/write/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { fetchEventSource } from '@microsoft/fetch-event-source' - -import { getAccessToken } from '@/utils/auth' -import { config } from '@/config/axios/config' -import { AiWriteTypeEnum } from '@/views/ai/utils/constants' -import request from '@/config/axios' - -export interface WriteVO { - type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:鎾板啓 2:鍥炲 - prompt: string // 鍐欎綔鍐呭鎻愮ず 1銆傛挵鍐� 2鍥炲 - originalContent: string // 鍘熸枃 - length: number // 闀垮害 - format: number // 鏍煎紡 - tone: number // 璇皵 - language: number // 璇█ - userId?: number // 鐢ㄦ埛缂栧彿 - platform?: string // 骞冲彴 - model?: string // 妯″瀷 - generatedContent?: string // 鐢熸垚鐨勫唴瀹� - errorMessage?: string // 閿欒淇℃伅 - createTime?: Date // 鍒涘缓鏃堕棿 -} - -export interface AiWritePageReqVO extends PageParam { - userId?: number // 鐢ㄦ埛缂栧彿 - type?: AiWriteTypeEnum // 鍐欎綔绫诲瀷 - platform?: string // 骞冲彴 - createTime?: [string, string] // 鍒涘缓鏃堕棿 -} - -export interface AiWriteRespVo { - id: number - userId: number - type: number - platform: string - model: string - prompt: string - generatedContent: string - originalContent: string - length: number - format: number - tone: number - language: number - errorMessage: string - createTime: string -} - -export const WriteApi = { - writeStream: ({ - data, - onClose, - onMessage, - onError, - ctrl - }: { - data: WriteVO - onMessage?: (res: any) => void - onError?: (...args: any[]) => void - onClose?: (...args: any[]) => void - ctrl: AbortController - }) => { - const token = getAccessToken() - return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, { - method: 'post', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - }, - openWhenHidden: true, - body: JSON.stringify(data), - onmessage: onMessage, - onerror: onError, - onclose: onClose, - signal: ctrl.signal - }) - }, - // 鑾峰彇鍐欎綔鍒楄〃 - getWritePage: (params: AiWritePageReqVO) => { - return request.get<PageResult<AiWriteRespVo[]>>({ url: `/ai/write/page`, params }) - }, - // 鍒犻櫎鍐欎綔 - deleteWrite(id: number) { - return request.delete({ url: `/ai/write/delete`, params: { id } }) - } -} diff --git a/src/api/bpm/activity/index.ts b/src/api/bpm/activity/index.ts deleted file mode 100644 index 870d0d6..0000000 --- a/src/api/bpm/activity/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import request from '@/config/axios' - -export const getActivityList = async (params) => { - return await request.get({ - url: '/bpm/activity/list', - params - }) -} diff --git a/src/api/bpm/category/index.ts b/src/api/bpm/category/index.ts deleted file mode 100644 index d1e109c..0000000 --- a/src/api/bpm/category/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import request from '@/config/axios' - -// BPM 娴佺▼鍒嗙被 VO -export interface CategoryVO { - id: number // 鍒嗙被缂栧彿 - name: string // 鍒嗙被鍚� - code: string // 鍒嗙被鏍囧織 - status: number // 鍒嗙被鐘舵�� - sort: number // 鍒嗙被鎺掑簭 -} - -// BPM 娴佺▼鍒嗙被 API -export const CategoryApi = { - // 鏌ヨ娴佺▼鍒嗙被鍒嗛〉 - getCategoryPage: async (params: any) => { - return await request.get({ url: `/bpm/category/page`, params }) - }, - - // 鏌ヨ娴佺▼鍒嗙被鍒楄〃 - getCategorySimpleList: async () => { - return await request.get({ url: `/bpm/category/simple-list` }) - }, - - // 鏌ヨ娴佺▼鍒嗙被璇︽儏 - getCategory: async (id: number) => { - return await request.get({ url: `/bpm/category/get?id=` + id }) - }, - - // 鏂板娴佺▼鍒嗙被 - createCategory: async (data: CategoryVO) => { - return await request.post({ url: `/bpm/category/create`, data }) - }, - - // 淇敼娴佺▼鍒嗙被 - updateCategory: async (data: CategoryVO) => { - return await request.put({ url: `/bpm/category/update`, data }) - }, - - // 鍒犻櫎娴佺▼鍒嗙被 - deleteCategory: async (id: number) => { - return await request.delete({ url: `/bpm/category/delete?id=` + id }) - } -} diff --git a/src/api/bpm/definition/index.ts b/src/api/bpm/definition/index.ts deleted file mode 100644 index caedba1..0000000 --- a/src/api/bpm/definition/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import request from '@/config/axios' - -export const getProcessDefinition = async (id?: string, key?: string) => { - return await request.get({ - url: '/bpm/process-definition/get', - params: { id, key } - }) -} - -export const getProcessDefinitionPage = async (params) => { - return await request.get({ - url: '/bpm/process-definition/page', - params - }) -} - -export const getProcessDefinitionList = async (params) => { - return await request.get({ - url: '/bpm/process-definition/list', - params - }) -} diff --git a/src/api/bpm/form/index.ts b/src/api/bpm/form/index.ts deleted file mode 100644 index 7fce11f..0000000 --- a/src/api/bpm/form/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import request from '@/config/axios' - -export type FormVO = { - id: number - name: string - conf: string - fields: string[] - status: number - remark: string - createTime: string -} - -// 鍒涘缓宸ヤ綔娴佺殑琛ㄥ崟瀹氫箟 -export const createForm = async (data: FormVO) => { - return await request.post({ - url: '/bpm/form/create', - data: data - }) -} - -// 鏇存柊宸ヤ綔娴佺殑琛ㄥ崟瀹氫箟 -export const updateForm = async (data: FormVO) => { - return await request.put({ - url: '/bpm/form/update', - data: data - }) -} - -// 鍒犻櫎宸ヤ綔娴佺殑琛ㄥ崟瀹氫箟 -export const deleteForm = async (id: number) => { - return await request.delete({ - url: '/bpm/form/delete?id=' + id - }) -} - -// 鑾峰緱宸ヤ綔娴佺殑琛ㄥ崟瀹氫箟 -export const getForm = async (id: number) => { - return await request.get({ - url: '/bpm/form/get?id=' + id - }) -} - -// 鑾峰緱宸ヤ綔娴佺殑琛ㄥ崟瀹氫箟鍒嗛〉 -export const getFormPage = async (params) => { - return await request.get({ - url: '/bpm/form/page', - params - }) -} - -// 鑾峰緱鍔ㄦ�佽〃鍗曠殑绮剧畝鍒楄〃 -export const getFormSimpleList = async () => { - return await request.get({ - url: '/bpm/form/simple-list' - }) -} diff --git a/src/api/bpm/leave/index.ts b/src/api/bpm/leave/index.ts deleted file mode 100644 index 4f374b2..0000000 --- a/src/api/bpm/leave/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import request from '@/config/axios' - -export type LeaveVO = { - id: number - status: number - type: number - reason: string - processInstanceId: string - startTime: string - endTime: string - createTime: string -} - -// 鍒涘缓璇峰亣鐢宠 -export const createLeave = async (data: LeaveVO) => { - return await request.post({ url: '/bpm/oa/leave/create', data: data }) -} - -// 鑾峰緱璇峰亣鐢宠 -export const getLeave = async (id: number) => { - return await request.get({ url: '/bpm/oa/leave/get?id=' + id }) -} - -// 鑾峰緱璇峰亣鐢宠鍒嗛〉 -export const getLeavePage = async (params: PageParam) => { - return await request.get({ url: '/bpm/oa/leave/page', params }) -} diff --git a/src/api/bpm/model/index.ts b/src/api/bpm/model/index.ts deleted file mode 100644 index 2b484a6..0000000 --- a/src/api/bpm/model/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import request from '@/config/axios' - -export type ProcessDefinitionVO = { - id: string - version: number - deploymentTIme: string - suspensionState: number - formType?: number -} - -export type ModelVO = { - id: number - formName: string - key: string - name: string - description: string - category: string - formType: number - formId: number - formCustomCreatePath: string - formCustomViewPath: string - processDefinition: ProcessDefinitionVO - status: number - remark: string - createTime: string - bpmnXml: string -} - -export const getModelPage = async (params) => { - return await request.get({ url: '/bpm/model/page', params }) -} - -export const getModel = async (id: number) => { - return await request.get({ url: '/bpm/model/get?id=' + id }) -} - -export const updateModel = async (data: ModelVO) => { - return await request.put({ url: '/bpm/model/update', data: data }) -} - -// 浠诲姟鐘舵�佷慨鏀� -export const updateModelState = async (id: number, state: number) => { - const data = { - id: id, - state: state - } - return await request.put({ url: '/bpm/model/update-state', data: data }) -} - -export const createModel = async (data: ModelVO) => { - return await request.post({ url: '/bpm/model/create', data: data }) -} - -export const deleteModel = async (id: number) => { - return await request.delete({ url: '/bpm/model/delete?id=' + id }) -} - -export const deployModel = async (id: number) => { - return await request.post({ url: '/bpm/model/deploy?id=' + id }) -} diff --git a/src/api/bpm/processExpression/index.ts b/src/api/bpm/processExpression/index.ts deleted file mode 100644 index af6a737..0000000 --- a/src/api/bpm/processExpression/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import request from '@/config/axios' - -// BPM 娴佺▼琛ㄨ揪寮� VO -export interface ProcessExpressionVO { - id: number // 缂栧彿 - name: string // 琛ㄨ揪寮忓悕瀛� - status: number // 琛ㄨ揪寮忕姸鎬� - expression: string // 琛ㄨ揪寮� -} - -// BPM 娴佺▼琛ㄨ揪寮� API -export const ProcessExpressionApi = { - // 鏌ヨBPM 娴佺▼琛ㄨ揪寮忓垎椤� - getProcessExpressionPage: async (params: any) => { - return await request.get({ url: `/bpm/process-expression/page`, params }) - }, - - // 鏌ヨBPM 娴佺▼琛ㄨ揪寮忚鎯� - getProcessExpression: async (id: number) => { - return await request.get({ url: `/bpm/process-expression/get?id=` + id }) - }, - - // 鏂板BPM 娴佺▼琛ㄨ揪寮� - createProcessExpression: async (data: ProcessExpressionVO) => { - return await request.post({ url: `/bpm/process-expression/create`, data }) - }, - - // 淇敼BPM 娴佺▼琛ㄨ揪寮� - updateProcessExpression: async (data: ProcessExpressionVO) => { - return await request.put({ url: `/bpm/process-expression/update`, data }) - }, - - // 鍒犻櫎BPM 娴佺▼琛ㄨ揪寮� - deleteProcessExpression: async (id: number) => { - return await request.delete({ url: `/bpm/process-expression/delete?id=` + id }) - }, - - // 瀵煎嚭BPM 娴佺▼琛ㄨ揪寮� Excel - exportProcessExpression: async (params) => { - return await request.download({ url: `/bpm/process-expression/export-excel`, params }) - } -} \ No newline at end of file diff --git a/src/api/bpm/processInstance/index.ts b/src/api/bpm/processInstance/index.ts deleted file mode 100644 index 9122b2b..0000000 --- a/src/api/bpm/processInstance/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -import request from '@/config/axios' -import { ProcessDefinitionVO } from '@/api/bpm/model' - -export type Task = { - id: string - name: string -} - -export type ProcessInstanceVO = { - id: number - name: string - processDefinitionId: string - category: string - result: number - tasks: Task[] - fields: string[] - status: number - remark: string - businessKey: string - createTime: string - endTime: string - processDefinition?: ProcessDefinitionVO -} - -export const getProcessInstanceMyPage = async (params: any) => { - return await request.get({ url: '/bpm/process-instance/my-page', params }) -} - -export const getProcessInstanceManagerPage = async (params: any) => { - return await request.get({ url: '/bpm/process-instance/manager-page', params }) -} - -export const createProcessInstance = async (data) => { - return await request.post({ url: '/bpm/process-instance/create', data: data }) -} - -export const cancelProcessInstanceByStartUser = async (id: number, reason: string) => { - const data = { - id: id, - reason: reason - } - return await request.delete({ url: '/bpm/process-instance/cancel-by-start-user', data: data }) -} - -export const cancelProcessInstanceByAdmin = async (id: number, reason: string) => { - const data = { - id: id, - reason: reason - } - return await request.delete({ url: '/bpm/process-instance/cancel-by-admin', data: data }) -} - -export const getProcessInstance = async (id: string) => { - return await request.get({ url: '/bpm/process-instance/get?id=' + id }) -} - -export const getProcessInstanceCopyPage = async (params: any) => { - return await request.get({ url: '/bpm/process-instance/copy/page', params }) -} diff --git a/src/api/bpm/processListener/index.ts b/src/api/bpm/processListener/index.ts deleted file mode 100644 index dabaa47..0000000 --- a/src/api/bpm/processListener/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import request from '@/config/axios' - -// BPM 娴佺▼鐩戝惉鍣� VO -export interface ProcessListenerVO { - id: number // 缂栧彿 - name: string // 鐩戝惉鍣ㄥ悕瀛� - type: string // 鐩戝惉鍣ㄧ被鍨� - status: number // 鐩戝惉鍣ㄧ姸鎬� - event: string // 鐩戝惉浜嬩欢 - valueType: string // 鐩戝惉鍣ㄥ�肩被鍨� - value: string // 鐩戝惉鍣ㄥ�� -} - -// BPM 娴佺▼鐩戝惉鍣� API -export const ProcessListenerApi = { - // 鏌ヨ娴佺▼鐩戝惉鍣ㄥ垎椤� - getProcessListenerPage: async (params: any) => { - return await request.get({ url: `/bpm/process-listener/page`, params }) - }, - - // 鏌ヨ娴佺▼鐩戝惉鍣ㄨ鎯� - getProcessListener: async (id: number) => { - return await request.get({ url: `/bpm/process-listener/get?id=` + id }) - }, - - // 鏂板娴佺▼鐩戝惉鍣� - createProcessListener: async (data: ProcessListenerVO) => { - return await request.post({ url: `/bpm/process-listener/create`, data }) - }, - - // 淇敼娴佺▼鐩戝惉鍣� - updateProcessListener: async (data: ProcessListenerVO) => { - return await request.put({ url: `/bpm/process-listener/update`, data }) - }, - - // 鍒犻櫎娴佺▼鐩戝惉鍣� - deleteProcessListener: async (id: number) => { - return await request.delete({ url: `/bpm/process-listener/delete?id=` + id }) - } -} diff --git a/src/api/bpm/task/index.ts b/src/api/bpm/task/index.ts deleted file mode 100644 index f3cda9f..0000000 --- a/src/api/bpm/task/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -import request from '@/config/axios' - -export type TaskVO = { - id: number -} - -export const getTaskTodoPage = async (params: any) => { - return await request.get({ url: '/bpm/task/todo-page', params }) -} - -export const getTaskDonePage = async (params: any) => { - return await request.get({ url: '/bpm/task/done-page', params }) -} - -export const getTaskManagerPage = async (params: any) => { - return await request.get({ url: '/bpm/task/manager-page', params }) -} - -export const approveTask = async (data: any) => { - return await request.put({ url: '/bpm/task/approve', data }) -} - -export const rejectTask = async (data: any) => { - return await request.put({ url: '/bpm/task/reject', data }) -} - -export const getTaskListByProcessInstanceId = async (processInstanceId: string) => { - return await request.get({ - url: '/bpm/task/list-by-process-instance-id?processInstanceId=' + processInstanceId - }) -} - -// 鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐� -export const getTaskListByReturn = async (id: string) => { - return await request.get({ url: '/bpm/task/list-by-return', params: { id } }) -} - -// 鍥為�� -export const returnTask = async (data: any) => { - return await request.put({ url: '/bpm/task/return', data }) -} - -// 濮旀淳 -export const delegateTask = async (data: any) => { - return await request.put({ url: '/bpm/task/delegate', data }) -} - -// 杞淳 -export const transferTask = async (data: any) => { - return await request.put({ url: '/bpm/task/transfer', data }) -} - -// 鍔犵 -export const signCreateTask = async (data: any) => { - return await request.put({ url: '/bpm/task/create-sign', data }) -} - -// 鍑忕 -export const signDeleteTask = async (data: any) => { - return await request.delete({ url: '/bpm/task/delete-sign', data }) -} - -// 鑾峰彇鍑忕浠诲姟鍒楄〃 -export const getChildrenTaskList = async (id: string) => { - return await request.get({ url: '/bpm/task/list-by-parent-task-id?parentTaskId=' + id }) -} diff --git a/src/api/bpm/userGroup/index.ts b/src/api/bpm/userGroup/index.ts deleted file mode 100644 index 7d12755..0000000 --- a/src/api/bpm/userGroup/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import request from '@/config/axios' - -export type UserGroupVO = { - id: number - name: string - description: string - userIds: number[] - status: number - remark: string - createTime: string -} - -// 鍒涘缓鐢ㄦ埛缁� -export const createUserGroup = async (data: UserGroupVO) => { - return await request.post({ - url: '/bpm/user-group/create', - data: data - }) -} - -// 鏇存柊鐢ㄦ埛缁� -export const updateUserGroup = async (data: UserGroupVO) => { - return await request.put({ - url: '/bpm/user-group/update', - data: data - }) -} - -// 鍒犻櫎鐢ㄦ埛缁� -export const deleteUserGroup = async (id: number) => { - return await request.delete({ url: '/bpm/user-group/delete?id=' + id }) -} - -// 鑾峰緱鐢ㄦ埛缁� -export const getUserGroup = async (id: number) => { - return await request.get({ url: '/bpm/user-group/get?id=' + id }) -} - -// 鑾峰緱鐢ㄦ埛缁勫垎椤� -export const getUserGroupPage = async (params) => { - return await request.get({ url: '/bpm/user-group/page', params }) -} - -// 鑾峰彇鐢ㄦ埛缁勭簿绠�淇℃伅鍒楄〃 -export const getUserGroupSimpleList = async (): Promise<UserGroupVO[]> => { - return await request.get({ url: '/bpm/user-group/simple-list' }) -} diff --git a/src/api/crm/business/index.ts b/src/api/crm/business/index.ts deleted file mode 100644 index 2420425..0000000 --- a/src/api/crm/business/index.ts +++ /dev/null @@ -1,98 +0,0 @@ -import request from '@/config/axios' -import { TransferReqVO } from '@/api/crm/permission' - -export interface BusinessVO { - id: number - name: string - customerId: number - customerName?: string - followUpStatus: boolean - contactLastTime: Date - contactNextTime: Date - ownerUserId: number - ownerUserName?: string // 璐熻矗浜虹殑鐢ㄦ埛鍚嶇О - ownerUserDept?: string // 璐熻矗浜虹殑閮ㄩ棬鍚嶇О - statusTypeId: number - statusTypeName?: string - statusId: number - statusName?: string - endStatus: number - endRemark: string - dealTime: Date - totalProductPrice: number - totalPrice: number - discountPercent: number - remark: string - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 - products?: [ - { - id: number - productId: number - productName: string - productNo: string - productUnit: number - productPrice: number - businessPrice: number - count: number - totalPrice: number - } - ] -} - -// 鏌ヨ CRM 鍟嗘満鍒楄〃 -export const getBusinessPage = async (params) => { - return await request.get({ url: `/crm/business/page`, params }) -} - -// 鏌ヨ CRM 鍟嗘満鍒楄〃锛屽熀浜庢寚瀹氬鎴� -export const getBusinessPageByCustomer = async (params) => { - return await request.get({ url: `/crm/business/page-by-customer`, params }) -} - -// 鏌ヨ CRM 鍟嗘満璇︽儏 -export const getBusiness = async (id: number) => { - return await request.get({ url: `/crm/business/get?id=` + id }) -} - -// 鑾峰緱 CRM 鍟嗘満鍒楄〃锛堢簿绠�锛� -export const getSimpleBusinessList = async () => { - return await request.get({ url: `/crm/business/simple-all-list` }) -} - -// 鏂板 CRM 鍟嗘満 -export const createBusiness = async (data: BusinessVO) => { - return await request.post({ url: `/crm/business/create`, data }) -} - -// 淇敼 CRM 鍟嗘満 -export const updateBusiness = async (data: BusinessVO) => { - return await request.put({ url: `/crm/business/update`, data }) -} - -// 淇敼 CRM 鍟嗘満鐘舵�� -export const updateBusinessStatus = async (data: BusinessVO) => { - return await request.put({ url: `/crm/business/update-status`, data }) -} - -// 鍒犻櫎 CRM 鍟嗘満 -export const deleteBusiness = async (id: number) => { - return await request.delete({ url: `/crm/business/delete?id=` + id }) -} - -// 瀵煎嚭 CRM 鍟嗘満 Excel -export const exportBusiness = async (params) => { - return await request.download({ url: `/crm/business/export-excel`, params }) -} - -// 鑱旂郴浜哄叧鑱斿晢鏈哄垪琛� -export const getBusinessPageByContact = async (params) => { - return await request.get({ url: `/crm/business/page-by-contact`, params }) -} - -// 鍟嗘満杞Щ -export const transferBusiness = async (data: TransferReqVO) => { - return await request.put({ url: '/crm/business/transfer', data }) -} diff --git a/src/api/crm/business/status/index.ts b/src/api/crm/business/status/index.ts deleted file mode 100644 index cddaa5a..0000000 --- a/src/api/crm/business/status/index.ts +++ /dev/null @@ -1,68 +0,0 @@ -import request from '@/config/axios' - -export interface BusinessStatusTypeVO { - id: number - name: string - deptIds: number[] - statuses?: { - id: number - name: string - percent: number - } -} - -export const DEFAULT_STATUSES = [ - { - endStatus: 1, - key: '缁撴潫', - name: '璧㈠崟', - percent: 100 - }, - { - endStatus: 2, - key: '缁撴潫', - name: '杈撳崟', - percent: 0 - }, - { - endStatus: 3, - key: '缁撴潫', - name: '鏃犳晥', - percent: 0 - } -] - -// 鏌ヨ鍟嗘満鐘舵�佺粍鍒楄〃 -export const getBusinessStatusPage = async (params: any) => { - return await request.get({ url: `/crm/business-status/page`, params }) -} - -// 鏂板鍟嗘満鐘舵�佺粍 -export const createBusinessStatus = async (data: BusinessStatusTypeVO) => { - return await request.post({ url: `/crm/business-status/create`, data }) -} - -// 淇敼鍟嗘満鐘舵�佺粍 -export const updateBusinessStatus = async (data: BusinessStatusTypeVO) => { - return await request.put({ url: `/crm/business-status/update`, data }) -} - -// 鏌ヨ鍟嗘満鐘舵�佺被鍨嬭鎯� -export const getBusinessStatus = async (id: number) => { - return await request.get({ url: `/crm/business-status/get?id=` + id }) -} - -// 鍒犻櫎鍟嗘満鐘舵�� -export const deleteBusinessStatus = async (id: number) => { - return await request.delete({ url: `/crm/business-status/delete?id=` + id }) -} - -// 鑾峰緱鍟嗘満鐘舵�佺粍鍒楄〃 -export const getBusinessStatusTypeSimpleList = async () => { - return await request.get({ url: `/crm/business-status/type-simple-list` }) -} - -// 鑾峰緱鍟嗘満闃舵鍒楄〃 -export const getBusinessStatusSimpleList = async (typeId: number) => { - return await request.get({ url: `/crm/business-status/status-simple-list`, params: { typeId } }) -} diff --git a/src/api/crm/clue/index.ts b/src/api/crm/clue/index.ts deleted file mode 100644 index 9736514..0000000 --- a/src/api/crm/clue/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import request from '@/config/axios' -import { TransferReqVO } from '@/api/crm/permission' - -export interface ClueVO { - id: number // 缂栧彿 - name: string // 绾跨储鍚嶇О - followUpStatus: boolean // 璺熻繘鐘舵�� - contactLastTime: Date // 鏈�鍚庤窡杩涙椂闂� - contactLastContent: string // 鏈�鍚庤窡杩涘唴瀹� - contactNextTime: Date // 涓嬫鑱旂郴鏃堕棿 - ownerUserId: number // 璐熻矗浜虹殑鐢ㄦ埛缂栧彿 - ownerUserName?: string // 璐熻矗浜虹殑鐢ㄦ埛鍚嶇О - ownerUserDept?: string // 璐熻矗浜虹殑閮ㄩ棬鍚嶇О - transformStatus: boolean // 杞寲鐘舵�� - customerId: number // 瀹㈡埛缂栧彿 - customerName?: string // 瀹㈡埛鍚嶇О - mobile: string // 鎵嬫満鍙� - telephone: string // 鐢佃瘽 - qq: string // QQ - wechat: string // wechat - email: string // email - areaId: number // 鎵�鍦ㄥ湴 - areaName?: string // 鎵�鍦ㄥ湴鍚嶇О - detailAddress: string // 璇︾粏鍦板潃 - industryId: number // 鎵�灞炶涓� - level: number // 瀹㈡埛绛夌骇 - source: number // 瀹㈡埛鏉ユ簮 - remark: string // 澶囨敞 - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 -} - -// 鏌ヨ绾跨储鍒楄〃 -export const getCluePage = async (params: any) => { - return await request.get({ url: `/crm/clue/page`, params }) -} - -// 鏌ヨ绾跨储璇︽儏 -export const getClue = async (id: number) => { - return await request.get({ url: `/crm/clue/get?id=` + id }) -} - -// 鏂板绾跨储 -export const createClue = async (data: ClueVO) => { - return await request.post({ url: `/crm/clue/create`, data }) -} - -// 淇敼绾跨储 -export const updateClue = async (data: ClueVO) => { - return await request.put({ url: `/crm/clue/update`, data }) -} - -// 鍒犻櫎绾跨储 -export const deleteClue = async (id: number) => { - return await request.delete({ url: `/crm/clue/delete?id=` + id }) -} - -// 瀵煎嚭绾跨储 Excel -export const exportClue = async (params) => { - return await request.download({ url: `/crm/clue/export-excel`, params }) -} - -// 绾跨储杞Щ -export const transferClue = async (data: TransferReqVO) => { - return await request.put({ url: '/crm/clue/transfer', data }) -} - -// 绾跨储杞寲涓哄鎴� -export const transformClue = async (id: number) => { - return await request.put({ url: '/crm/clue/transform', params: { id } }) -} - -// 鑾峰緱鍒嗛厤缁欐垜鐨勩�佸緟璺熻繘鐨勭嚎绱㈡暟閲� -export const getFollowClueCount = async () => { - return await request.get({ url: '/crm/clue/follow-count' }) -} diff --git a/src/api/crm/contact/index.ts b/src/api/crm/contact/index.ts deleted file mode 100644 index 7c24dfa..0000000 --- a/src/api/crm/contact/index.ts +++ /dev/null @@ -1,113 +0,0 @@ -import request from '@/config/axios' -import { TransferReqVO } from '@/api/crm/permission' - -export interface ContactVO { - id: number // 缂栧彿 - name: string // 鑱旂郴浜哄悕绉� - customerId: number // 瀹㈡埛缂栧彿 - customerName?: string // 瀹㈡埛鍚嶇О - contactLastTime: Date // 鏈�鍚庤窡杩涙椂闂� - contactLastContent: string // 鏈�鍚庤窡杩涘唴瀹� - contactNextTime: Date // 涓嬫鑱旂郴鏃堕棿 - ownerUserId: number // 璐熻矗浜虹殑鐢ㄦ埛缂栧彿 - ownerUserName?: string // 璐熻矗浜虹殑鐢ㄦ埛鍚嶇О - ownerUserDept?: string // 璐熻矗浜虹殑閮ㄩ棬鍚嶇О - mobile: string // 鎵嬫満鍙� - telephone: string // 鐢佃瘽 - qq: string // QQ - wechat: string // wechat - email: string // email - areaId: number // 鎵�鍦ㄥ湴 - areaName?: string // 鎵�鍦ㄥ湴鍚嶇О - detailAddress: string // 璇︾粏鍦板潃 - sex: number // 鎬у埆 - master: boolean // 鏄惁涓昏仈绯讳汉 - post: string // 鑱屽姟 - parentId: number // 涓婄骇鑱旂郴浜虹紪鍙� - parentName?: string // 涓婄骇鑱旂郴浜哄悕绉� - remark: string // 澶囨敞 - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 -} - -export interface ContactBusinessReqVO { - contactId: number - businessIds: number[] -} - -export interface ContactBusiness2ReqVO { - businessId: number - contactIds: number[] -} - -// 鏌ヨ CRM 鑱旂郴浜哄垪琛� -export const getContactPage = async (params) => { - return await request.get({ url: `/crm/contact/page`, params }) -} - -// 鏌ヨ CRM 鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾瀹㈡埛 -export const getContactPageByCustomer = async (params: any) => { - return await request.get({ url: `/crm/contact/page-by-customer`, params }) -} - -// 鏌ヨ CRM 鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾鍟嗘満 -export const getContactPageByBusiness = async (params: any) => { - return await request.get({ url: `/crm/contact/page-by-business`, params }) -} - -// 鏌ヨ CRM 鑱旂郴浜鸿鎯� -export const getContact = async (id: number) => { - return await request.get({ url: `/crm/contact/get?id=` + id }) -} - -// 鏂板 CRM 鑱旂郴浜� -export const createContact = async (data: ContactVO) => { - return await request.post({ url: `/crm/contact/create`, data }) -} - -// 淇敼 CRM 鑱旂郴浜� -export const updateContact = async (data: ContactVO) => { - return await request.put({ url: `/crm/contact/update`, data }) -} - -// 鍒犻櫎 CRM 鑱旂郴浜� -export const deleteContact = async (id: number) => { - return await request.delete({ url: `/crm/contact/delete?id=` + id }) -} - -// 瀵煎嚭 CRM 鑱旂郴浜� Excel -export const exportContact = async (params) => { - return await request.download({ url: `/crm/contact/export-excel`, params }) -} - -// 鑾峰緱 CRM 鑱旂郴浜哄垪琛紙绮剧畝锛� -export const getSimpleContactList = async () => { - return await request.get({ url: `/crm/contact/simple-all-list` }) -} - -// 鎵归噺鏂板鑱旂郴浜哄晢鏈哄叧鑱� -export const createContactBusinessList = async (data: ContactBusinessReqVO) => { - return await request.post({ url: `/crm/contact/create-business-list`, data }) -} - -// 鎵归噺鏂板鑱旂郴浜哄晢鏈哄叧鑱� -export const createContactBusinessList2 = async (data: ContactBusiness2ReqVO) => { - return await request.post({ url: `/crm/contact/create-business-list2`, data }) -} - -// 瑙i櫎鑱旂郴浜哄晢鏈哄叧鑱� -export const deleteContactBusinessList = async (data: ContactBusinessReqVO) => { - return await request.delete({ url: `/crm/contact/delete-business-list`, data }) -} - -// 瑙i櫎鑱旂郴浜哄晢鏈哄叧鑱� -export const deleteContactBusinessList2 = async (data: ContactBusiness2ReqVO) => { - return await request.delete({ url: `/crm/contact/delete-business-list2`, data }) -} - -// 鑱旂郴浜鸿浆绉� -export const transferContact = async (data: TransferReqVO) => { - return await request.put({ url: '/crm/contact/transfer', data }) -} diff --git a/src/api/crm/contract/config/index.ts b/src/api/crm/contract/config/index.ts deleted file mode 100644 index 0c7ad20..0000000 --- a/src/api/crm/contract/config/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import request from '@/config/axios' - -export interface ContractConfigVO { - notifyEnabled?: boolean - notifyDays?: number -} - -// 鑾峰彇鍚堝悓閰嶇疆 -export const getContractConfig = async () => { - return await request.get({ url: `/crm/contract-config/get` }) -} - -// 鏇存柊鍚堝悓閰嶇疆 -export const saveContractConfig = async (data: ContractConfigVO) => { - return await request.put({ url: `/crm/contract-config/save`, data }) -} diff --git a/src/api/crm/contract/index.ts b/src/api/crm/contract/index.ts deleted file mode 100644 index 7028b77..0000000 --- a/src/api/crm/contract/index.ts +++ /dev/null @@ -1,114 +0,0 @@ -import request from '@/config/axios' -import { TransferReqVO } from '@/api/crm/permission' - -export interface ContractVO { - id: number - name: string - no: string - customerId: number - customerName?: string - businessId: number - businessName: string - contactLastTime: Date - ownerUserId: number - ownerUserName?: string - ownerUserDeptName?: string - processInstanceId: number - auditStatus: number - orderDate: Date - startTime: Date - endTime: Date - totalProductPrice: number - discountPercent: number - totalPrice: number - totalReceivablePrice: number - signContactId: number - signContactName?: string - signUserId: number - signUserName: string - remark: string - createTime?: Date - creator: string - creatorName: string - updateTime?: Date - products?: [ - { - id: number - productId: number - productName: string - productNo: string - productUnit: number - productPrice: number - contractPrice: number - count: number - totalPrice: number - } - ] -} - -// 鏌ヨ CRM 鍚堝悓鍒楄〃 -export const getContractPage = async (params) => { - return await request.get({ url: `/crm/contract/page`, params }) -} - -// 鏌ヨ CRM 鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾瀹㈡埛 -export const getContractPageByCustomer = async (params: any) => { - return await request.get({ url: `/crm/contract/page-by-customer`, params }) -} - -// 鏌ヨ CRM 鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾鍟嗘満 -export const getContractPageByBusiness = async (params: any) => { - return await request.get({ url: `/crm/contract/page-by-business`, params }) -} - -// 鏌ヨ CRM 鍚堝悓璇︽儏 -export const getContract = async (id: number) => { - return await request.get({ url: `/crm/contract/get?id=` + id }) -} - -// 鏌ヨ CRM 鍚堝悓涓嬫媺鍒楄〃 -export const getContractSimpleList = async (customerId: number) => { - return await request.get({ - url: `/crm/contract/simple-list?customerId=${customerId}` - }) -} - -// 鏂板 CRM 鍚堝悓 -export const createContract = async (data: ContractVO) => { - return await request.post({ url: `/crm/contract/create`, data }) -} - -// 淇敼 CRM 鍚堝悓 -export const updateContract = async (data: ContractVO) => { - return await request.put({ url: `/crm/contract/update`, data }) -} - -// 鍒犻櫎 CRM 鍚堝悓 -export const deleteContract = async (id: number) => { - return await request.delete({ url: `/crm/contract/delete?id=` + id }) -} - -// 瀵煎嚭 CRM 鍚堝悓 Excel -export const exportContract = async (params) => { - return await request.download({ url: `/crm/contract/export-excel`, params }) -} - -// 鎻愪氦瀹℃牳 -export const submitContract = async (id: number) => { - return await request.put({ url: `/crm/contract/submit?id=${id}` }) -} - -// 鍚堝悓杞Щ -export const transferContract = async (data: TransferReqVO) => { - return await request.put({ url: '/crm/contract/transfer', data }) -} - -// 鑾峰緱寰呭鏍稿悎鍚屾暟閲� -export const getAuditContractCount = async () => { - return await request.get({ url: '/crm/contract/audit-count' }) -} - -// 鑾峰緱鍗冲皢鍒版湡锛堟彁閱掞級鐨勫悎鍚屾暟閲� -export const getRemindContractCount = async () => { - return await request.get({ url: '/crm/contract/remind-count' }) -} diff --git a/src/api/crm/customer/index.ts b/src/api/crm/customer/index.ts deleted file mode 100644 index d149d4e..0000000 --- a/src/api/crm/customer/index.ts +++ /dev/null @@ -1,132 +0,0 @@ -import request from '@/config/axios' -import { TransferReqVO } from '@/api/crm/permission' - -export interface CustomerVO { - id: number // 缂栧彿 - name: string // 瀹㈡埛鍚嶇О - followUpStatus: boolean // 璺熻繘鐘舵�� - contactLastTime: Date // 鏈�鍚庤窡杩涙椂闂� - contactLastContent: string // 鏈�鍚庤窡杩涘唴瀹� - contactNextTime: Date // 涓嬫鑱旂郴鏃堕棿 - ownerUserId: number // 璐熻矗浜虹殑鐢ㄦ埛缂栧彿 - ownerUserName?: string // 璐熻矗浜虹殑鐢ㄦ埛鍚嶇О - ownerUserDept?: string // 璐熻矗浜虹殑閮ㄩ棬鍚嶇О - lockStatus?: boolean - dealStatus?: boolean - mobile: string // 鎵嬫満鍙� - telephone: string // 鐢佃瘽 - qq: string // QQ - wechat: string // wechat - email: string // email - areaId: number // 鎵�鍦ㄥ湴 - areaName?: string // 鎵�鍦ㄥ湴鍚嶇О - detailAddress: string // 璇︾粏鍦板潃 - industryId: number // 鎵�灞炶涓� - level: number // 瀹㈡埛绛夌骇 - source: number // 瀹㈡埛鏉ユ簮 - remark: string // 澶囨敞 - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 -} - -// 鏌ヨ瀹㈡埛鍒楄〃 -export const getCustomerPage = async (params) => { - return await request.get({ url: `/crm/customer/page`, params }) -} - -// 杩涘叆鍏捣瀹㈡埛鎻愰啋鐨勫鎴峰垪琛� -export const getPutPoolRemindCustomerPage = async (params) => { - return await request.get({ url: `/crm/customer/put-pool-remind-page`, params }) -} - -// 鑾峰緱寰呰繘鍏ュ叕娴峰鎴锋暟閲� -export const getPutPoolRemindCustomerCount = async () => { - return await request.get({ url: `/crm/customer/put-pool-remind-count` }) -} - -// 鑾峰緱浠婃棩闇�鑱旂郴瀹㈡埛鏁伴噺 -export const getTodayContactCustomerCount = async () => { - return await request.get({ url: `/crm/customer/today-contact-count` }) -} - -// 鑾峰緱鍒嗛厤缁欐垜銆佸緟璺熻繘鐨勭嚎绱㈡暟閲忕殑瀹㈡埛鏁伴噺 -export const getFollowCustomerCount = async () => { - return await request.get({ url: `/crm/customer/follow-count` }) -} - -// 鏌ヨ瀹㈡埛璇︽儏 -export const getCustomer = async (id: number) => { - return await request.get({ url: `/crm/customer/get?id=` + id }) -} - -// 鏂板瀹㈡埛 -export const createCustomer = async (data: CustomerVO) => { - return await request.post({ url: `/crm/customer/create`, data }) -} - -// 淇敼瀹㈡埛 -export const updateCustomer = async (data: CustomerVO) => { - return await request.put({ url: `/crm/customer/update`, data }) -} - -// 鏇存柊瀹㈡埛鐨勬垚浜ょ姸鎬� -export const updateCustomerDealStatus = async (id: number, dealStatus: boolean) => { - return await request.put({ url: `/crm/customer/update-deal-status`, params: { id, dealStatus } }) -} - -// 鍒犻櫎瀹㈡埛 -export const deleteCustomer = async (id: number) => { - return await request.delete({ url: `/crm/customer/delete?id=` + id }) -} - -// 瀵煎嚭瀹㈡埛 Excel -export const exportCustomer = async (params: any) => { - return await request.download({ url: `/crm/customer/export-excel`, params }) -} - -// 涓嬭浇瀹㈡埛瀵煎叆妯℃澘 -export const importCustomerTemplate = () => { - return request.download({ url: '/crm/customer/get-import-template' }) -} - -// 瀵煎叆瀹㈡埛 -export const handleImport = async (formData) => { - return await request.upload({ url: `/crm/customer/import`, data: formData }) -} - -// 瀹㈡埛鍒楄〃 -export const getCustomerSimpleList = async () => { - return await request.get({ url: `/crm/customer/simple-list` }) -} - -// ======================= 涓氬姟鎿嶄綔 ======================= - -// 瀹㈡埛杞Щ -export const transferCustomer = async (data: TransferReqVO) => { - return await request.put({ url: '/crm/customer/transfer', data }) -} - -// 閿佸畾/瑙i攣瀹㈡埛 -export const lockCustomer = async (id: number, lockStatus: boolean) => { - return await request.put({ url: `/crm/customer/lock`, data: { id, lockStatus } }) -} - -// 棰嗗彇鍏捣瀹㈡埛 -export const receiveCustomer = async (ids: any[]) => { - return await request.put({ url: '/crm/customer/receive', params: { ids: ids.join(',') } }) -} - -// 鍒嗛厤鍏捣缁欏搴旇礋璐d汉 -export const distributeCustomer = async (ids: any[], ownerUserId: number) => { - return await request.put({ - url: '/crm/customer/distribute', - data: { ids: ids, ownerUserId } - }) -} - -// 瀹㈡埛鏀惧叆鍏捣 -export const putCustomerPool = async (id: number) => { - return await request.put({ url: `/crm/customer/put-pool?id=${id}` }) -} diff --git a/src/api/crm/customer/limitConfig/index.ts b/src/api/crm/customer/limitConfig/index.ts deleted file mode 100644 index 8677632..0000000 --- a/src/api/crm/customer/limitConfig/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/config/axios' - -export interface CustomerLimitConfigVO { - id?: number - type?: number - userIds?: string - deptIds?: string - maxCount?: number - dealCountEnabled?: boolean -} - -/** - * 瀹㈡埛闄愬埗閰嶇疆绫诲瀷 - */ -export enum LimitConfType { - /** - * 鎷ユ湁瀹㈡埛鏁伴檺鍒� - */ - CUSTOMER_QUANTITY_LIMIT = 1, - /** - * 閿佸畾瀹㈡埛鏁伴檺鍒� - */ - CUSTOMER_LOCK_LIMIT = 2 -} - -// 鏌ヨ瀹㈡埛闄愬埗閰嶇疆鍒楄〃 -export const getCustomerLimitConfigPage = async (params) => { - return await request.get({ url: `/crm/customer-limit-config/page`, params }) -} - -// 鏌ヨ瀹㈡埛闄愬埗閰嶇疆璇︽儏 -export const getCustomerLimitConfig = async (id: number) => { - return await request.get({ url: `/crm/customer-limit-config/get?id=` + id }) -} - -// 鏂板瀹㈡埛闄愬埗閰嶇疆 -export const createCustomerLimitConfig = async (data: CustomerLimitConfigVO) => { - return await request.post({ url: `/crm/customer-limit-config/create`, data }) -} - -// 淇敼瀹㈡埛闄愬埗閰嶇疆 -export const updateCustomerLimitConfig = async (data: CustomerLimitConfigVO) => { - return await request.put({ url: `/crm/customer-limit-config/update`, data }) -} - -// 鍒犻櫎瀹㈡埛闄愬埗閰嶇疆 -export const deleteCustomerLimitConfig = async (id: number) => { - return await request.delete({ url: `/crm/customer-limit-config/delete?id=` + id }) -} diff --git a/src/api/crm/customer/poolConfig/index.ts b/src/api/crm/customer/poolConfig/index.ts deleted file mode 100644 index b96e61f..0000000 --- a/src/api/crm/customer/poolConfig/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import request from '@/config/axios' - -export interface CustomerPoolConfigVO { - enabled?: boolean - contactExpireDays?: number - dealExpireDays?: number - notifyEnabled?: boolean - notifyDays?: number -} - -// 鑾峰彇瀹㈡埛鍏捣瑙勫垯璁剧疆 -export const getCustomerPoolConfig = async () => { - return await request.get({ url: `/crm/customer-pool-config/get` }) -} - -// 鏇存柊瀹㈡埛鍏捣瑙勫垯璁剧疆 -export const saveCustomerPoolConfig = async (data: CustomerPoolConfigVO) => { - return await request.put({ url: `/crm/customer-pool-config/save`, data }) -} diff --git a/src/api/crm/followup/index.ts b/src/api/crm/followup/index.ts deleted file mode 100644 index 414f3f7..0000000 --- a/src/api/crm/followup/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import request from '@/config/axios' - -// 璺熻繘璁板綍 VO -export interface FollowUpRecordVO { - id: number // 缂栧彿 - bizType: number // 鏁版嵁绫诲瀷 - bizId: number // 鏁版嵁缂栧彿 - type: number // 璺熻繘绫诲瀷 - content: string // 璺熻繘鍐呭 - picUrls: string[] // 鍥剧墖 - fileUrls: string[] // 闄勪欢 - nextTime: Date // 涓嬫鑱旂郴鏃堕棿 - businessIds: number[] // 鍏宠仈鐨勫晢鏈虹紪鍙锋暟缁� - businesses: { - id: number - name: string - }[] // 鍏宠仈鐨勫晢鏈烘暟缁� - contactIds: number[] // 鍏宠仈鐨勮仈绯讳汉缂栧彿鏁扮粍 - contacts: { - id: number - name: string - }[] // 鍏宠仈鐨勮仈绯讳汉鏁扮粍 - creator: string - creatorName?: string -} - -// 璺熻繘璁板綍 API -export const FollowUpRecordApi = { - // 鏌ヨ璺熻繘璁板綍鍒嗛〉 - getFollowUpRecordPage: async (params: any) => { - return await request.get({ url: `/crm/follow-up-record/page`, params }) - }, - - // 鏂板璺熻繘璁板綍 - createFollowUpRecord: async (data: FollowUpRecordVO) => { - return await request.post({ url: `/crm/follow-up-record/create`, data }) - }, - - // 鍒犻櫎璺熻繘璁板綍 - deleteFollowUpRecord: async (id: number) => { - return await request.delete({ url: `/crm/follow-up-record/delete?id=` + id }) - } -} diff --git a/src/api/crm/operateLog/index.ts b/src/api/crm/operateLog/index.ts deleted file mode 100644 index d0f25b6..0000000 --- a/src/api/crm/operateLog/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import request from '@/config/axios' - -export interface OperateLogVO extends PageParam { - bizType: number - bizId: number -} - -// 鑾峰緱鎿嶄綔鏃ュ織 -export const getOperateLogPage = async (params: OperateLogVO) => { - return await request.get({ url: `/crm/operate-log/page`, params }) -} diff --git a/src/api/crm/permission/index.ts b/src/api/crm/permission/index.ts deleted file mode 100644 index 4f88b14..0000000 --- a/src/api/crm/permission/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -import request from '@/config/axios' - -export interface PermissionVO { - id?: number // 鏁版嵁鏉冮檺缂栧彿 - userId: number // 鐢ㄦ埛缂栧彿 - bizType: number // Crm 绫诲瀷 - bizId: number // Crm 绫诲瀷鏁版嵁缂栧彿 - level: number // 鏉冮檺绾у埆 - toBizTypes?: number[] // 鍚屾椂娣诲姞鑷� - deptName?: string // 閮ㄩ棬鍚嶇О - nickname?: string // 鐢ㄦ埛鏄电О - postNames?: string[] // 宀椾綅鍚嶇О鏁扮粍 - createTime?: Date - ids?: number[] -} - -export interface TransferReqVO { - id: number // 妯″潡缂栧彿 - newOwnerUserId: number // 鏂拌礋璐d汉鐨勭敤鎴风紪鍙� - oldOwnerPermissionLevel?: number // 鑰佽礋璐d汉鍔犲叆鍥㈤槦鍚庣殑鏉冮檺绾у埆 - toBizTypes?: number[] // 杞Щ瀹㈡埛鏃讹紝闇�瑕侀澶栨湁銆愯仈绯讳汉銆戙�愬晢鏈恒�戙�愬悎鍚屻�戠殑 checkbox 閫夋嫨 -} - -/** - * CRM 涓氬姟绫诲瀷鏋氫妇 - * - * @author HUIHUI - */ -export enum BizTypeEnum { - CRM_CLUE = 1, // 绾跨储 - CRM_CUSTOMER = 2, // 瀹㈡埛 - CRM_CONTACT = 3, // 鑱旂郴浜� - CRM_BUSINESS = 4, // 鍟嗘満 - CRM_CONTRACT = 5, // 鍚堝悓 - CRM_PRODUCT = 6, // 浜у搧 - CRM_RECEIVABLE = 7, // 鍥炴 - CRM_RECEIVABLE_PLAN = 8 // 鍥炴璁″垝 -} - -/** - * CRM 鏁版嵁鏉冮檺绾у埆鏋氫妇 - */ -export enum PermissionLevelEnum { - OWNER = 1, // 璐熻矗浜� - READ = 2, // 鍙 - WRITE = 3 // 璇诲啓 -} - -// 鑾峰緱鏁版嵁鏉冮檺鍒楄〃锛堟煡璇㈠洟闃熸垚鍛樺垪琛級 -export const getPermissionList = async (params) => { - return await request.get({ url: `/crm/permission/list`, params }) -} - -// 鍒涘缓鏁版嵁鏉冮檺锛堟柊澧炲洟闃熸垚鍛橈級 -export const createPermission = async (data: PermissionVO) => { - return await request.post({ url: `/crm/permission/create`, data }) -} - -// 缂栬緫鏁版嵁鏉冮檺锛堜慨鏀瑰洟闃熸垚鍛樻潈闄愮骇鍒級 -export const updatePermission = async (data) => { - return await request.put({ url: `/crm/permission/update`, data }) -} - -// 鍒犻櫎鏁版嵁鏉冮檺锛堝垹闄ゅ洟闃熸垚鍛橈級 -export const deletePermissionBatch = async (val: number[]) => { - return await request.delete({ url: '/crm/permission/delete?ids=' + val.join(',') }) -} - -// 鍒犻櫎鑷繁鐨勬暟鎹潈闄愶紙閫�鍑哄洟闃燂級 -export const deleteSelfPermission = async (id: number) => { - return await request.delete({ url: '/crm/permission/delete-self?id=' + id }) -} diff --git a/src/api/crm/product/category/index.ts b/src/api/crm/product/category/index.ts deleted file mode 100644 index 6341d1b..0000000 --- a/src/api/crm/product/category/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import request from '@/config/axios' - -// TODO @zange锛氭尓鍒� product 涓嬶紝寤轰釜 category 鍖咃紝鎸繘鍘诲搱锛� -export interface ProductCategoryVO { - id: number - name: string - parentId: number -} - -// 鏌ヨ浜у搧鍒嗙被璇︽儏 -export const getProductCategory = async (id: number) => { - return await request.get({ url: `/crm/product-category/get?id=` + id }) -} - -// 鏂板浜у搧鍒嗙被 -export const createProductCategory = async (data: ProductCategoryVO) => { - return await request.post({ url: `/crm/product-category/create`, data }) -} - -// 淇敼浜у搧鍒嗙被 -export const updateProductCategory = async (data: ProductCategoryVO) => { - return await request.put({ url: `/crm/product-category/update`, data }) -} - -// 鍒犻櫎浜у搧鍒嗙被 -export const deleteProductCategory = async (id: number) => { - return await request.delete({ url: `/crm/product-category/delete?id=` + id }) -} - -// 浜у搧鍒嗙被鍒楄〃 -export const getProductCategoryList = async (params) => { - return await request.get({ url: `/crm/product-category/list`, params }) -} diff --git a/src/api/crm/product/index.ts b/src/api/crm/product/index.ts deleted file mode 100644 index f0c2328..0000000 --- a/src/api/crm/product/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/config/axios' - -export interface ProductVO { - id: number - name: string - no: string - unit: number - price: number - status: number - categoryId: number - categoryName?: string - description: string - ownerUserId: number -} - -// 鏌ヨ浜у搧鍒楄〃 -export const getProductPage = async (params) => { - return await request.get({ url: `/crm/product/page`, params }) -} - -// 鑾峰緱浜у搧绮剧畝鍒楄〃 -export const getProductSimpleList = async () => { - return await request.get({ url: `/crm/product/simple-list` }) -} - -// 鏌ヨ浜у搧璇︽儏 -export const getProduct = async (id: number) => { - return await request.get({ url: `/crm/product/get?id=` + id }) -} - -// 鏂板浜у搧 -export const createProduct = async (data: ProductVO) => { - return await request.post({ url: `/crm/product/create`, data }) -} - -// 淇敼浜у搧 -export const updateProduct = async (data: ProductVO) => { - return await request.put({ url: `/crm/product/update`, data }) -} - -// 鍒犻櫎浜у搧 -export const deleteProduct = async (id: number) => { - return await request.delete({ url: `/crm/product/delete?id=` + id }) -} - -// 瀵煎嚭浜у搧 Excel -export const exportProduct = async (params) => { - return await request.download({ url: `/crm/product/export-excel`, params }) -} diff --git a/src/api/crm/receivable/index.ts b/src/api/crm/receivable/index.ts deleted file mode 100644 index 32ecd25..0000000 --- a/src/api/crm/receivable/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -import request from '@/config/axios' - -export interface ReceivableVO { - id: number - no: string - planId?: number - customerId?: number - customerName?: string - contractId?: number - contract?: { - id?: number - name?: string - no: string - totalPrice: number - } - auditStatus: number - processInstanceId: number - returnTime: Date - returnType: number - price: number - ownerUserId: number - ownerUserName?: string - remark: string - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 -} - -// 鏌ヨ鍥炴鍒楄〃 -export const getReceivablePage = async (params) => { - return await request.get({ url: `/crm/receivable/page`, params }) -} - -// 鏌ヨ鍥炴鍒楄〃 -export const getReceivablePageByCustomer = async (params) => { - return await request.get({ url: `/crm/receivable/page-by-customer`, params }) -} - -// 鏌ヨ鍥炴璇︽儏 -export const getReceivable = async (id: number) => { - return await request.get({ url: `/crm/receivable/get?id=` + id }) -} - -// 鏂板鍥炴 -export const createReceivable = async (data: ReceivableVO) => { - return await request.post({ url: `/crm/receivable/create`, data }) -} - -// 淇敼鍥炴 -export const updateReceivable = async (data: ReceivableVO) => { - return await request.put({ url: `/crm/receivable/update`, data }) -} - -// 鍒犻櫎鍥炴 -export const deleteReceivable = async (id: number) => { - return await request.delete({ url: `/crm/receivable/delete?id=` + id }) -} - -// 瀵煎嚭鍥炴 Excel -export const exportReceivable = async (params) => { - return await request.download({ url: `/crm/receivable/export-excel`, params }) -} - -// 鎻愪氦瀹℃牳 -export const submitReceivable = async (id: number) => { - return await request.put({ url: `/crm/receivable/submit?id=${id}` }) -} - -// 鑾峰緱寰呭鏍稿洖娆炬暟閲� -export const getAuditReceivableCount = async () => { - return await request.get({ url: '/crm/receivable/audit-count' }) -} diff --git a/src/api/crm/receivable/plan/index.ts b/src/api/crm/receivable/plan/index.ts deleted file mode 100644 index 770b347..0000000 --- a/src/api/crm/receivable/plan/index.ts +++ /dev/null @@ -1,74 +0,0 @@ -import request from '@/config/axios' - -export interface ReceivablePlanVO { - id: number - period: number - receivableId: number - price: number - returnTime: Date - remindDays: number - returnType: number - remindTime: Date - customerId: number - customerName?: string - contractId?: number - contractNo?: string - ownerUserId: number - ownerUserName?: string - remark: string - creator: string // 鍒涘缓浜� - creatorName?: string // 鍒涘缓浜哄悕绉� - createTime: Date // 鍒涘缓鏃堕棿 - updateTime: Date // 鏇存柊鏃堕棿 - receivable?: { - price: number - returnTime: Date - } -} - -// 鏌ヨ鍥炴璁″垝鍒楄〃 -export const getReceivablePlanPage = async (params) => { - return await request.get({ url: `/crm/receivable-plan/page`, params }) -} - -// 鏌ヨ鍥炴璁″垝鍒楄〃 -export const getReceivablePlanPageByCustomer = async (params) => { - return await request.get({ url: `/crm/receivable-plan/page-by-customer`, params }) -} - -// 鏌ヨ鍥炴璁″垝璇︽儏 -export const getReceivablePlan = async (id: number) => { - return await request.get({ url: `/crm/receivable-plan/get?id=` + id }) -} - -// 鏌ヨ鍥炴璁″垝涓嬫媺鏁版嵁 -export const getReceivablePlanSimpleList = async (customerId: number, contractId: number) => { - return await request.get({ - url: `/crm/receivable-plan/simple-list?customerId=${customerId}&contractId=${contractId}` - }) -} - -// 鏂板鍥炴璁″垝 -export const createReceivablePlan = async (data: ReceivablePlanVO) => { - return await request.post({ url: `/crm/receivable-plan/create`, data }) -} - -// 淇敼鍥炴璁″垝 -export const updateReceivablePlan = async (data: ReceivablePlanVO) => { - return await request.put({ url: `/crm/receivable-plan/update`, data }) -} - -// 鍒犻櫎鍥炴璁″垝 -export const deleteReceivablePlan = async (id: number) => { - return await request.delete({ url: `/crm/receivable-plan/delete?id=` + id }) -} - -// 瀵煎嚭鍥炴璁″垝 Excel -export const exportReceivablePlan = async (params) => { - return await request.download({ url: `/crm/receivable-plan/export-excel`, params }) -} - -// 鑾峰緱寰呭洖娆炬彁閱掓暟閲� -export const getReceivablePlanRemindCount = async () => { - return await request.get({ url: '/crm/receivable-plan/remind-count' }) -} diff --git a/src/api/crm/statistics/customer.ts b/src/api/crm/statistics/customer.ts deleted file mode 100644 index c2092e4..0000000 --- a/src/api/crm/statistics/customer.ts +++ /dev/null @@ -1,168 +0,0 @@ -import request from '@/config/axios' - -export interface CrmStatisticsCustomerSummaryByDateRespVO { - time: string - customerCreateCount: number - customerDealCount: number -} - -export interface CrmStatisticsCustomerSummaryByUserRespVO { - ownerUserName: string - customerCreateCount: number - customerDealCount: number - contractPrice: number - receivablePrice: number -} - -export interface CrmStatisticsFollowUpSummaryByDateRespVO { - time: string - followUpRecordCount: number - followUpCustomerCount: number -} - -export interface CrmStatisticsFollowUpSummaryByUserRespVO { - ownerUserName: string - followupRecordCount: number - followupCustomerCount: number -} - -export interface CrmStatisticsFollowUpSummaryByTypeRespVO { - followUpType: string - followUpRecordCount: number -} - -export interface CrmStatisticsCustomerContractSummaryRespVO { - customerName: string - contractName: string - totalPrice: number - receivablePrice: number - customerType: string - customerSource: string - ownerUserName: string - creatorUserName: string - createTime: Date - orderDate: Date -} - -export interface CrmStatisticsPoolSummaryByDateRespVO { - time: string - customerPutCount: number - customerTakeCount: number -} - -export interface CrmStatisticsPoolSummaryByUserRespVO { - ownerUserName: string - customerPutCount: number - customerTakeCount: number -} - -export interface CrmStatisticsCustomerDealCycleByDateRespVO { - time: string - customerDealCycle: number -} - -export interface CrmStatisticsCustomerDealCycleByUserRespVO { - ownerUserName: string - customerDealCycle: number - customerDealCount: number -} - -export interface CrmStatisticsCustomerDealCycleByAreaRespVO { - areaName: string - customerDealCycle: number - customerDealCount: number -} - -export interface CrmStatisticsCustomerDealCycleByProductRespVO { - productName: string - customerDealCycle: number - customerDealCount: number -} - -// 瀹㈡埛鍒嗘瀽 API -export const StatisticsCustomerApi = { - // 1.1 瀹㈡埛鎬婚噺鍒嗘瀽(鎸夋棩鏈�) - getCustomerSummaryByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-summary-by-date', - params - }) - }, - // 1.2 瀹㈡埛鎬婚噺鍒嗘瀽(鎸夌敤鎴�) - getCustomerSummaryByUser: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-summary-by-user', - params - }) - }, - // 2.1 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽(鎸夋棩鏈�) - getFollowUpSummaryByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-follow-up-summary-by-date', - params - }) - }, - // 2.2 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽(鎸夌敤鎴�) - getFollowUpSummaryByUser: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-follow-up-summary-by-user', - params - }) - }, - // 3.1 鑾峰彇瀹㈡埛璺熻繘鏂瑰紡缁熻鏁� - getFollowUpSummaryByType: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-follow-up-summary-by-type', - params - }) - }, - // 4.1 鍚堝悓鎽樿淇℃伅(瀹㈡埛杞寲鐜囬〉闈�) - getContractSummary: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-contract-summary', - params - }) - }, - // 5.1 鑾峰彇瀹㈡埛鍏捣鍒嗘瀽(鎸夋棩鏈�) - getPoolSummaryByDate: (param: any) => { - return request.get({ - url: '/crm/statistics-customer/get-pool-summary-by-date', - params: param - }) - }, - // 5.2 鑾峰彇瀹㈡埛鍏捣鍒嗘瀽(鎸夌敤鎴�) - getPoolSummaryByUser: (param: any) => { - return request.get({ - url: '/crm/statistics-customer/get-pool-summary-by-user', - params: param - }) - }, - // 6.1 鑾峰彇瀹㈡埛鎴愪氦鍛ㄦ湡(鎸夋棩鏈�) - getCustomerDealCycleByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-deal-cycle-by-date', - params - }) - }, - // 6.2 鑾峰彇瀹㈡埛鎴愪氦鍛ㄦ湡(鎸夌敤鎴�) - getCustomerDealCycleByUser: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-deal-cycle-by-user', - params - }) - }, - // 6.2 鑾峰彇瀹㈡埛鎴愪氦鍛ㄦ湡(鎸夌敤鎴�) - getCustomerDealCycleByArea: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-deal-cycle-by-area', - params - }) - }, - // 6.2 鑾峰彇瀹㈡埛鎴愪氦鍛ㄦ湡(鎸夌敤鎴�) - getCustomerDealCycleByProduct: (params: any) => { - return request.get({ - url: '/crm/statistics-customer/get-customer-deal-cycle-by-product', - params - }) - } -} diff --git a/src/api/crm/statistics/funnel.ts b/src/api/crm/statistics/funnel.ts deleted file mode 100644 index 574a5f4..0000000 --- a/src/api/crm/statistics/funnel.ts +++ /dev/null @@ -1,58 +0,0 @@ -import request from '@/config/axios' - -export interface CrmStatisticFunnelRespVO { - customerCount: number // 瀹㈡埛鏁� - businessCount: number // 鍟嗘満鏁� - businessWinCount: number // 璧㈠崟鏁� -} - -export interface CrmStatisticsBusinessSummaryByDateRespVO { - time: string // 鏃堕棿 - businessCreateCount: number // 鍟嗘満鏁� - totalPrice: number | string // 鍟嗘満閲戦 -} - -export interface CrmStatisticsBusinessInversionRateSummaryByDateRespVO { - time: string // 鏃堕棿 - businessCount: number // 鍟嗘満鏁伴噺 - businessWinCount: number // 璧㈠崟鍟嗘満鏁� -} - -// 瀹㈡埛鍒嗘瀽 API -export const StatisticFunnelApi = { - // 1. 鑾峰彇閿�鍞紡鏂楃粺璁℃暟鎹� - getFunnelSummary: (params: any) => { - return request.get({ - url: '/crm/statistics-funnel/get-funnel-summary', - params - }) - }, - // 2. 鑾峰彇鍟嗘満缁撴潫鐘舵�佺粺璁� - getBusinessSummaryByEndStatus: (params: any) => { - return request.get({ - url: '/crm/statistics-funnel/get-business-summary-by-end-status', - params - }) - }, - // 3. 鑾峰彇鏂板鍟嗘満鍒嗘瀽(鎸夋棩鏈�) - getBusinessSummaryByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-funnel/get-business-summary-by-date', - params - }) - }, - // 4. 鑾峰彇鍟嗘満杞寲鐜囧垎鏋�(鎸夋棩鏈�) - getBusinessInversionRateSummaryByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-funnel/get-business-inversion-rate-summary-by-date', - params - }) - }, - // 5. 鑾峰彇鍟嗘満鍒楄〃(鎸夋棩鏈�) - getBusinessPageByDate: (params: any) => { - return request.get({ - url: '/crm/statistics-funnel/get-business-page-by-date', - params - }) - } -} diff --git a/src/api/crm/statistics/performance.ts b/src/api/crm/statistics/performance.ts deleted file mode 100644 index 2318505..0000000 --- a/src/api/crm/statistics/performance.ts +++ /dev/null @@ -1,33 +0,0 @@ -import request from '@/config/axios' - -export interface StatisticsPerformanceRespVO { - time: string - currentMonthCount: number - lastMonthCount: number - lastYearCount: number -} - -// 鎺掕 API -export const StatisticsPerformanceApi = { - // 鍛樺伐鑾峰緱鍚堝悓閲戦缁熻 - getContractPricePerformance: (params: any) => { - return request.get({ - url: '/crm/statistics-performance/get-contract-price-performance', - params - }) - }, - // 鍛樺伐鑾峰緱鍥炴缁熻 - getReceivablePricePerformance: (params: any) => { - return request.get({ - url: '/crm/statistics-performance/get-receivable-price-performance', - params - }) - }, - //鍛樺伐鑾峰緱绛剧害鍚堝悓鏁伴噺缁熻 - getContractCountPerformance: (params: any) => { - return request.get({ - url: '/crm/statistics-performance/get-contract-count-performance', - params - }) - } -} diff --git a/src/api/crm/statistics/portrait.ts b/src/api/crm/statistics/portrait.ts deleted file mode 100644 index c7a2572..0000000 --- a/src/api/crm/statistics/portrait.ts +++ /dev/null @@ -1,60 +0,0 @@ -import request from '@/config/axios' - -export interface CrmStatisticCustomerBaseRespVO { - customerCount: number - dealCount: number - dealPortion: string | number -} - -export interface CrmStatisticCustomerIndustryRespVO extends CrmStatisticCustomerBaseRespVO { - industryId: number - industryPortion: string | number -} - -export interface CrmStatisticCustomerSourceRespVO extends CrmStatisticCustomerBaseRespVO { - source: number - sourcePortion: string | number -} - -export interface CrmStatisticCustomerLevelRespVO extends CrmStatisticCustomerBaseRespVO { - level: number - levelPortion: string | number -} - -export interface CrmStatisticCustomerAreaRespVO extends CrmStatisticCustomerBaseRespVO { - areaId: number - areaName: string - areaPortion: string | number -} - -// 瀹㈡埛鍒嗘瀽 API -export const StatisticsPortraitApi = { - // 1. 鑾峰彇瀹㈡埛琛屼笟缁熻鏁版嵁 - getCustomerIndustry: (params: any) => { - return request.get({ - url: '/crm/statistics-portrait/get-customer-industry-summary', - params - }) - }, - // 2. 鑾峰彇瀹㈡埛鏉ユ簮缁熻鏁版嵁 - getCustomerSource: (params: any) => { - return request.get({ - url: '/crm/statistics-portrait/get-customer-source-summary', - params - }) - }, - // 3. 鑾峰彇瀹㈡埛绾у埆缁熻鏁版嵁 - getCustomerLevel: (params: any) => { - return request.get({ - url: '/crm/statistics-portrait/get-customer-level-summary', - params - }) - }, - // 4. 鑾峰彇瀹㈡埛鍦板尯缁熻鏁版嵁 - getCustomerArea: (params: any) => { - return request.get({ - url: '/crm/statistics-portrait/get-customer-area-summary', - params - }) - } -} diff --git a/src/api/crm/statistics/rank.ts b/src/api/crm/statistics/rank.ts deleted file mode 100644 index a9b355e..0000000 --- a/src/api/crm/statistics/rank.ts +++ /dev/null @@ -1,67 +0,0 @@ -import request from '@/config/axios' - -export interface StatisticsRankRespVO { - count: number - nickname: string - deptName: string -} - -// 鎺掕 API -export const StatisticsRankApi = { - // 鑾峰緱鍚堝悓鎺掕姒� - getContractPriceRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-contract-price-rank', - params - }) - }, - // 鑾峰緱鍥炴鎺掕姒� - getReceivablePriceRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-receivable-price-rank', - params - }) - }, - // 绛剧害鍚堝悓鎺掕 - getContractCountRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-contract-count-rank', - params - }) - }, - // 浜у搧閿�閲忔帓琛� - getProductSalesRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-product-sales-rank', - params - }) - }, - // 鏂板瀹㈡埛鏁版帓琛� - getCustomerCountRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-customer-count-rank', - params - }) - }, - // 鏂板鑱旂郴浜烘暟鎺掕 - getContactsCountRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-contacts-count-rank', - params - }) - }, - // 璺熻繘娆℃暟鎺掕 - getFollowCountRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-follow-count-rank', - params - }) - }, - // 璺熻繘瀹㈡埛鏁版帓琛� - getFollowCustomerCountRank: (params: any) => { - return request.get({ - url: '/crm/statistics-rank/get-follow-customer-count-rank', - params - }) - } -} diff --git a/src/api/erp/finance/account/index.ts b/src/api/erp/finance/account/index.ts deleted file mode 100644 index a62b180..0000000 --- a/src/api/erp/finance/account/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -// ERP 缁撶畻璐︽埛 VO -export interface AccountVO { - id: number // 缁撶畻璐︽埛缂栧彿 - no: string // 璐︽埛缂栫爜 - remark: string // 澶囨敞 - status: number // 寮�鍚姸鎬� - sort: number // 鎺掑簭 - defaultStatus: boolean // 鏄惁榛樿 - name: string // 璐︽埛鍚嶇О -} - -// ERP 缁撶畻璐︽埛 API -export const AccountApi = { - // 鏌ヨ缁撶畻璐︽埛鍒嗛〉 - getAccountPage: async (params: any) => { - return await request.get({ url: `/erp/account/page`, params }) - }, - - // 鏌ヨ缁撶畻璐︽埛绮剧畝鍒楄〃 - getAccountSimpleList: async () => { - return await request.get({ url: `/erp/account/simple-list` }) - }, - - // 鏌ヨ缁撶畻璐︽埛璇︽儏 - getAccount: async (id: number) => { - return await request.get({ url: `/erp/account/get?id=` + id }) - }, - - // 鏂板缁撶畻璐︽埛 - createAccount: async (data: AccountVO) => { - return await request.post({ url: `/erp/account/create`, data }) - }, - - // 淇敼缁撶畻璐︽埛 - updateAccount: async (data: AccountVO) => { - return await request.put({ url: `/erp/account/update`, data }) - }, - - // 淇敼缁撶畻璐︽埛榛樿鐘舵�� - updateAccountDefaultStatus: async (id: number, defaultStatus: boolean) => { - return await request.put({ - url: `/erp/account/update-default-status`, - params: { - id, - defaultStatus - } - }) - }, - - // 鍒犻櫎缁撶畻璐︽埛 - deleteAccount: async (id: number) => { - return await request.delete({ url: `/erp/account/delete?id=` + id }) - }, - - // 瀵煎嚭缁撶畻璐︽埛 Excel - exportAccount: async (params: any) => { - return await request.download({ url: `/erp/account/export-excel`, params }) - } -} diff --git a/src/api/erp/finance/payment/index.ts b/src/api/erp/finance/payment/index.ts deleted file mode 100644 index c6749db..0000000 --- a/src/api/erp/finance/payment/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -// ERP 浠樻鍗� VO -export interface FinancePaymentVO { - id: number // 浠樻鍗曠紪鍙� - no: string // 浠樻鍗曞彿 - supplierId: number // 渚涘簲鍟嗙紪鍙� - paymentTime: Date // 浠樻鏃堕棿 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 浠樻鍗� API -export const FinancePaymentApi = { - // 鏌ヨ浠樻鍗曞垎椤� - getFinancePaymentPage: async (params: any) => { - return await request.get({ url: `/erp/finance-payment/page`, params }) - }, - - // 鏌ヨ浠樻鍗曡鎯� - getFinancePayment: async (id: number) => { - return await request.get({ url: `/erp/finance-payment/get?id=` + id }) - }, - - // 鏂板浠樻鍗� - createFinancePayment: async (data: FinancePaymentVO) => { - return await request.post({ url: `/erp/finance-payment/create`, data }) - }, - - // 淇敼浠樻鍗� - updateFinancePayment: async (data: FinancePaymentVO) => { - return await request.put({ url: `/erp/finance-payment/update`, data }) - }, - - // 鏇存柊浠樻鍗曠殑鐘舵�� - updateFinancePaymentStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/finance-payment/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎浠樻鍗� - deleteFinancePayment: async (ids: number[]) => { - return await request.delete({ - url: `/erp/finance-payment/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭浠樻鍗� Excel - exportFinancePayment: async (params: any) => { - return await request.download({ url: `/erp/finance-payment/export-excel`, params }) - } -} diff --git a/src/api/erp/finance/receipt/index.ts b/src/api/erp/finance/receipt/index.ts deleted file mode 100644 index 4de28ca..0000000 --- a/src/api/erp/finance/receipt/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -// ERP 鏀舵鍗� VO -export interface FinanceReceiptVO { - id: number // 鏀舵鍗曠紪鍙� - no: string // 鏀舵鍗曞彿 - customerId: number // 瀹㈡埛缂栧彿 - receiptTime: Date // 鏀舵鏃堕棿 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 鏀舵鍗� API -export const FinanceReceiptApi = { - // 鏌ヨ鏀舵鍗曞垎椤� - getFinanceReceiptPage: async (params: any) => { - return await request.get({ url: `/erp/finance-receipt/page`, params }) - }, - - // 鏌ヨ鏀舵鍗曡鎯� - getFinanceReceipt: async (id: number) => { - return await request.get({ url: `/erp/finance-receipt/get?id=` + id }) - }, - - // 鏂板鏀舵鍗� - createFinanceReceipt: async (data: FinanceReceiptVO) => { - return await request.post({ url: `/erp/finance-receipt/create`, data }) - }, - - // 淇敼鏀舵鍗� - updateFinanceReceipt: async (data: FinanceReceiptVO) => { - return await request.put({ url: `/erp/finance-receipt/update`, data }) - }, - - // 鏇存柊鏀舵鍗曠殑鐘舵�� - updateFinanceReceiptStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/finance-receipt/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎鏀舵鍗� - deleteFinanceReceipt: async (ids: number[]) => { - return await request.delete({ - url: `/erp/finance-receipt/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭鏀舵鍗� Excel - exportFinanceReceipt: async (params: any) => { - return await request.download({ url: `/erp/finance-receipt/export-excel`, params }) - } -} diff --git a/src/api/erp/product/category/index.ts b/src/api/erp/product/category/index.ts deleted file mode 100644 index d67ccff..0000000 --- a/src/api/erp/product/category/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/config/axios' - -// ERP 浜у搧鍒嗙被 VO -export interface ProductCategoryVO { - id: number // 鍒嗙被缂栧彿 - parentId: number // 鐖跺垎绫荤紪鍙� - name: string // 鍒嗙被鍚嶇О - code: string // 鍒嗙被缂栫爜 - sort: number // 鍒嗙被鎺掑簭 - status: number // 寮�鍚姸鎬� -} - -// ERP 浜у搧鍒嗙被 API -export const ProductCategoryApi = { - // 鏌ヨ浜у搧鍒嗙被鍒楄〃 - getProductCategoryList: async () => { - return await request.get({ url: `/erp/product-category/list` }) - }, - - // 鏌ヨ浜у搧鍒嗙被绮剧畝鍒楄〃 - getProductCategorySimpleList: async () => { - return await request.get({ url: `/erp/product-category/simple-list` }) - }, - - // 鏌ヨ浜у搧鍒嗙被璇︽儏 - getProductCategory: async (id: number) => { - return await request.get({ url: `/erp/product-category/get?id=` + id }) - }, - - // 鏂板浜у搧鍒嗙被 - createProductCategory: async (data: ProductCategoryVO) => { - return await request.post({ url: `/erp/product-category/create`, data }) - }, - - // 淇敼浜у搧鍒嗙被 - updateProductCategory: async (data: ProductCategoryVO) => { - return await request.put({ url: `/erp/product-category/update`, data }) - }, - - // 鍒犻櫎浜у搧鍒嗙被 - deleteProductCategory: async (id: number) => { - return await request.delete({ url: `/erp/product-category/delete?id=` + id }) - }, - - // 瀵煎嚭浜у搧鍒嗙被 Excel - exportProductCategory: async (params) => { - return await request.download({ url: `/erp/product-category/export-excel`, params }) - } -} diff --git a/src/api/erp/product/product/index.ts b/src/api/erp/product/product/index.ts deleted file mode 100644 index 1136282..0000000 --- a/src/api/erp/product/product/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import request from '@/config/axios' - -// ERP 浜у搧 VO -export interface ProductVO { - id: number // 浜у搧缂栧彿 - name: string // 浜у搧鍚嶇О - barCode: string // 浜у搧鏉$爜 - categoryId: number // 浜у搧绫诲瀷缂栧彿 - unitId: number // 鍗曚綅缂栧彿 - unitName?: string // 鍗曚綅鍚嶅瓧 - status: number // 浜у搧鐘舵�� - standard: string // 浜у搧瑙勬牸 - remark: string // 浜у搧澶囨敞 - expiryDay: number // 淇濊川鏈熷ぉ鏁� - weight: number // 閲嶉噺锛坘g锛� - purchasePrice: number // 閲囪喘浠锋牸锛屽崟浣嶏細鍏� - salePrice: number // 閿�鍞环鏍硷紝鍗曚綅锛氬厓 - minPrice: number // 鏈�浣庝环鏍硷紝鍗曚綅锛氬厓 -} - -// ERP 浜у搧 API -export const ProductApi = { - // 鏌ヨ浜у搧鍒嗛〉 - getProductPage: async (params: any) => { - return await request.get({ url: `/erp/product/page`, params }) - }, - - // 鏌ヨ浜у搧绮剧畝鍒楄〃 - getProductSimpleList: async () => { - return await request.get({ url: `/erp/product/simple-list` }) - }, - - // 鏌ヨ浜у搧璇︽儏 - getProduct: async (id: number) => { - return await request.get({ url: `/erp/product/get?id=` + id }) - }, - - // 鏂板浜у搧 - createProduct: async (data: ProductVO) => { - return await request.post({ url: `/erp/product/create`, data }) - }, - - // 淇敼浜у搧 - updateProduct: async (data: ProductVO) => { - return await request.put({ url: `/erp/product/update`, data }) - }, - - // 鍒犻櫎浜у搧 - deleteProduct: async (id: number) => { - return await request.delete({ url: `/erp/product/delete?id=` + id }) - }, - - // 瀵煎嚭浜у搧 Excel - exportProduct: async (params) => { - return await request.download({ url: `/erp/product/export-excel`, params }) - } -} diff --git a/src/api/erp/product/unit/index.ts b/src/api/erp/product/unit/index.ts deleted file mode 100644 index 1e1c8ac..0000000 --- a/src/api/erp/product/unit/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import request from '@/config/axios' - -// ERP 浜у搧鍗曚綅 VO -export interface ProductUnitVO { - id: number // 鍗曚綅缂栧彿 - name: string // 鍗曚綅鍚嶅瓧 - status: number // 鍗曚綅鐘舵�� -} - -// ERP 浜у搧鍗曚綅 API -export const ProductUnitApi = { - // 鏌ヨ浜у搧鍗曚綅鍒嗛〉 - getProductUnitPage: async (params: any) => { - return await request.get({ url: `/erp/product-unit/page`, params }) - }, - - // 鏌ヨ浜у搧鍗曚綅绮剧畝鍒楄〃 - getProductUnitSimpleList: async () => { - return await request.get({ url: `/erp/product-unit/simple-list` }) - }, - - // 鏌ヨ浜у搧鍗曚綅璇︽儏 - getProductUnit: async (id: number) => { - return await request.get({ url: `/erp/product-unit/get?id=` + id }) - }, - - // 鏂板浜у搧鍗曚綅 - createProductUnit: async (data: ProductUnitVO) => { - return await request.post({ url: `/erp/product-unit/create`, data }) - }, - - // 淇敼浜у搧鍗曚綅 - updateProductUnit: async (data: ProductUnitVO) => { - return await request.put({ url: `/erp/product-unit/update`, data }) - }, - - // 鍒犻櫎浜у搧鍗曚綅 - deleteProductUnit: async (id: number) => { - return await request.delete({ url: `/erp/product-unit/delete?id=` + id }) - }, - - // 瀵煎嚭浜у搧鍗曚綅 Excel - exportProductUnit: async (params) => { - return await request.download({ url: `/erp/product-unit/export-excel`, params }) - } -} diff --git a/src/api/erp/purchase/in/index.ts b/src/api/erp/purchase/in/index.ts deleted file mode 100644 index f94708d..0000000 --- a/src/api/erp/purchase/in/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import request from '@/config/axios' - -// ERP 閲囪喘鍏ュ簱 VO -export interface PurchaseInVO { - id: number // 鍏ュ簱宸ュ崟缂栧彿 - no: string // 閲囪喘鍏ュ簱鍙� - customerId: number // 瀹㈡埛缂栧彿 - inTime: Date // 鍏ュ簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 - outCount: number // 閲囪喘鍑哄簱鏁伴噺 - returnCount: number // 閲囪喘閫�璐ф暟閲� -} - -// ERP 閲囪喘鍏ュ簱 API -export const PurchaseInApi = { - // 鏌ヨ閲囪喘鍏ュ簱鍒嗛〉 - getPurchaseInPage: async (params: any) => { - return await request.get({ url: `/erp/purchase-in/page`, params }) - }, - - // 鏌ヨ閲囪喘鍏ュ簱璇︽儏 - getPurchaseIn: async (id: number) => { - return await request.get({ url: `/erp/purchase-in/get?id=` + id }) - }, - - // 鏂板閲囪喘鍏ュ簱 - createPurchaseIn: async (data: PurchaseInVO) => { - return await request.post({ url: `/erp/purchase-in/create`, data }) - }, - - // 淇敼閲囪喘鍏ュ簱 - updatePurchaseIn: async (data: PurchaseInVO) => { - return await request.put({ url: `/erp/purchase-in/update`, data }) - }, - - // 鏇存柊閲囪喘鍏ュ簱鐨勭姸鎬� - updatePurchaseInStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/purchase-in/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閲囪喘鍏ュ簱 - deletePurchaseIn: async (ids: number[]) => { - return await request.delete({ - url: `/erp/purchase-in/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閲囪喘鍏ュ簱 Excel - exportPurchaseIn: async (params: any) => { - return await request.download({ url: `/erp/purchase-in/export-excel`, params }) - } -} diff --git a/src/api/erp/purchase/order/index.ts b/src/api/erp/purchase/order/index.ts deleted file mode 100644 index ad3222f..0000000 --- a/src/api/erp/purchase/order/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import request from '@/config/axios' - -// ERP 閲囪喘璁㈠崟 VO -export interface PurchaseOrderVO { - id: number // 璁㈠崟宸ュ崟缂栧彿 - no: string // 閲囪喘璁㈠崟鍙� - customerId: number // 瀹㈡埛缂栧彿 - orderTime: Date // 璁㈠崟鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 - outCount: number // 閲囪喘鍑哄簱鏁伴噺 - returnCount: number // 閲囪喘閫�璐ф暟閲� -} - -// ERP 閲囪喘璁㈠崟 API -export const PurchaseOrderApi = { - // 鏌ヨ閲囪喘璁㈠崟鍒嗛〉 - getPurchaseOrderPage: async (params: any) => { - return await request.get({ url: `/erp/purchase-order/page`, params }) - }, - - // 鏌ヨ閲囪喘璁㈠崟璇︽儏 - getPurchaseOrder: async (id: number) => { - return await request.get({ url: `/erp/purchase-order/get?id=` + id }) - }, - - // 鏂板閲囪喘璁㈠崟 - createPurchaseOrder: async (data: PurchaseOrderVO) => { - return await request.post({ url: `/erp/purchase-order/create`, data }) - }, - - // 淇敼閲囪喘璁㈠崟 - updatePurchaseOrder: async (data: PurchaseOrderVO) => { - return await request.put({ url: `/erp/purchase-order/update`, data }) - }, - - // 鏇存柊閲囪喘璁㈠崟鐨勭姸鎬� - updatePurchaseOrderStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/purchase-order/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閲囪喘璁㈠崟 - deletePurchaseOrder: async (ids: number[]) => { - return await request.delete({ - url: `/erp/purchase-order/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閲囪喘璁㈠崟 Excel - exportPurchaseOrder: async (params: any) => { - return await request.download({ url: `/erp/purchase-order/export-excel`, params }) - } -} diff --git a/src/api/erp/purchase/return/index.ts b/src/api/erp/purchase/return/index.ts deleted file mode 100644 index 182e04e..0000000 --- a/src/api/erp/purchase/return/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import request from '@/config/axios' - -// ERP 閲囪喘閫�璐� VO -export interface PurchaseReturnVO { - id: number // 閲囪喘閫�璐х紪鍙� - no: string // 閲囪喘閫�璐у彿 - customerId: number // 瀹㈡埛缂栧彿 - returnTime: Date // 閫�璐ф椂闂� - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 閲囪喘閫�璐� API -export const PurchaseReturnApi = { - // 鏌ヨ閲囪喘閫�璐у垎椤� - getPurchaseReturnPage: async (params: any) => { - return await request.get({ url: `/erp/purchase-return/page`, params }) - }, - - // 鏌ヨ閲囪喘閫�璐ц鎯� - getPurchaseReturn: async (id: number) => { - return await request.get({ url: `/erp/purchase-return/get?id=` + id }) - }, - - // 鏂板閲囪喘閫�璐� - createPurchaseReturn: async (data: PurchaseReturnVO) => { - return await request.post({ url: `/erp/purchase-return/create`, data }) - }, - - // 淇敼閲囪喘閫�璐� - updatePurchaseReturn: async (data: PurchaseReturnVO) => { - return await request.put({ url: `/erp/purchase-return/update`, data }) - }, - - // 鏇存柊閲囪喘閫�璐х殑鐘舵�� - updatePurchaseReturnStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/purchase-return/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閲囪喘閫�璐� - deletePurchaseReturn: async (ids: number[]) => { - return await request.delete({ - url: `/erp/purchase-return/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閲囪喘閫�璐� Excel - exportPurchaseReturn: async (params: any) => { - return await request.download({ url: `/erp/purchase-return/export-excel`, params }) - } -} diff --git a/src/api/erp/purchase/supplier/index.ts b/src/api/erp/purchase/supplier/index.ts deleted file mode 100644 index 34729a5..0000000 --- a/src/api/erp/purchase/supplier/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import request from '@/config/axios' - -// ERP 渚涘簲鍟� VO -export interface SupplierVO { - id: number // 渚涘簲鍟嗙紪鍙� - name: string // 渚涘簲鍟嗗悕绉� - contact: string // 鑱旂郴浜� - mobile: string // 鎵嬫満鍙风爜 - telephone: string // 鑱旂郴鐢佃瘽 - email: string // 鐢靛瓙閭 - fax: string // 浼犵湡 - remark: string // 澶囨敞 - status: number // 寮�鍚姸鎬� - sort: number // 鎺掑簭 - taxNo: string // 绾崇◣浜鸿瘑鍒彿 - taxPercent: number // 绋庣巼 - bankName: string // 寮�鎴疯 - bankAccount: string // 寮�鎴疯处鍙� - bankAddress: string // 寮�鎴峰湴鍧� -} - -// ERP 渚涘簲鍟� API -export const SupplierApi = { - // 鏌ヨ渚涘簲鍟嗗垎椤� - getSupplierPage: async (params: any) => { - return await request.get({ url: `/erp/supplier/page`, params }) - }, - - // 鑾峰緱渚涘簲鍟嗙簿绠�鍒楄〃 - getSupplierSimpleList: async () => { - return await request.get({ url: `/erp/supplier/simple-list` }) - }, - - // 鏌ヨ渚涘簲鍟嗚鎯� - getSupplier: async (id: number) => { - return await request.get({ url: `/erp/supplier/get?id=` + id }) - }, - - // 鏂板渚涘簲鍟� - createSupplier: async (data: SupplierVO) => { - return await request.post({ url: `/erp/supplier/create`, data }) - }, - - // 淇敼渚涘簲鍟� - updateSupplier: async (data: SupplierVO) => { - return await request.put({ url: `/erp/supplier/update`, data }) - }, - - // 鍒犻櫎渚涘簲鍟� - deleteSupplier: async (id: number) => { - return await request.delete({ url: `/erp/supplier/delete?id=` + id }) - }, - - // 瀵煎嚭渚涘簲鍟� Excel - exportSupplier: async (params) => { - return await request.download({ url: `/erp/supplier/export-excel`, params }) - } -} diff --git a/src/api/erp/sale/customer/index.ts b/src/api/erp/sale/customer/index.ts deleted file mode 100644 index 3aaefb5..0000000 --- a/src/api/erp/sale/customer/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import request from '@/config/axios' - -// ERP 瀹㈡埛 VO -export interface CustomerVO { - id: number // 瀹㈡埛缂栧彿 - name: string // 瀹㈡埛鍚嶇О - contact: string // 鑱旂郴浜� - mobile: string // 鎵嬫満鍙风爜 - telephone: string // 鑱旂郴鐢佃瘽 - email: string // 鐢靛瓙閭 - fax: string // 浼犵湡 - remark: string // 澶囨敞 - status: number // 寮�鍚姸鎬� - sort: number // 鎺掑簭 - taxNo: string // 绾崇◣浜鸿瘑鍒彿 - taxPercent: number // 绋庣巼 - bankName: string // 寮�鎴疯 - bankAccount: string // 寮�鎴疯处鍙� - bankAddress: string // 寮�鎴峰湴鍧� -} - -// ERP 瀹㈡埛 API -export const CustomerApi = { - // 鏌ヨ瀹㈡埛鍒嗛〉 - getCustomerPage: async (params: any) => { - return await request.get({ url: `/erp/customer/page`, params }) - }, - - // 鏌ヨ瀹㈡埛绮剧畝鍒楄〃 - getCustomerSimpleList: async () => { - return await request.get({ url: `/erp/customer/simple-list` }) - }, - - // 鏌ヨ瀹㈡埛璇︽儏 - getCustomer: async (id: number) => { - return await request.get({ url: `/erp/customer/get?id=` + id }) - }, - - // 鏂板瀹㈡埛 - createCustomer: async (data: CustomerVO) => { - return await request.post({ url: `/erp/customer/create`, data }) - }, - - // 淇敼瀹㈡埛 - updateCustomer: async (data: CustomerVO) => { - return await request.put({ url: `/erp/customer/update`, data }) - }, - - // 鍒犻櫎瀹㈡埛 - deleteCustomer: async (id: number) => { - return await request.delete({ url: `/erp/customer/delete?id=` + id }) - }, - - // 瀵煎嚭瀹㈡埛 Excel - exportCustomer: async (params) => { - return await request.download({ url: `/erp/customer/export-excel`, params }) - } -} diff --git a/src/api/erp/sale/order/index.ts b/src/api/erp/sale/order/index.ts deleted file mode 100644 index 2d2ac53..0000000 --- a/src/api/erp/sale/order/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import request from '@/config/axios' - -// ERP 閿�鍞鍗� VO -export interface SaleOrderVO { - id: number // 璁㈠崟宸ュ崟缂栧彿 - no: string // 閿�鍞鍗曞彿 - customerId: number // 瀹㈡埛缂栧彿 - orderTime: Date // 璁㈠崟鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 - outCount: number // 閿�鍞嚭搴撴暟閲� - returnCount: number // 閿�鍞��璐ф暟閲� -} - -// ERP 閿�鍞鍗� API -export const SaleOrderApi = { - // 鏌ヨ閿�鍞鍗曞垎椤� - getSaleOrderPage: async (params: any) => { - return await request.get({ url: `/erp/sale-order/page`, params }) - }, - - // 鏌ヨ閿�鍞鍗曡鎯� - getSaleOrder: async (id: number) => { - return await request.get({ url: `/erp/sale-order/get?id=` + id }) - }, - - // 鏂板閿�鍞鍗� - createSaleOrder: async (data: SaleOrderVO) => { - return await request.post({ url: `/erp/sale-order/create`, data }) - }, - - // 淇敼閿�鍞鍗� - updateSaleOrder: async (data: SaleOrderVO) => { - return await request.put({ url: `/erp/sale-order/update`, data }) - }, - - // 鏇存柊閿�鍞鍗曠殑鐘舵�� - updateSaleOrderStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/sale-order/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閿�鍞鍗� - deleteSaleOrder: async (ids: number[]) => { - return await request.delete({ - url: `/erp/sale-order/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閿�鍞鍗� Excel - exportSaleOrder: async (params: any) => { - return await request.download({ url: `/erp/sale-order/export-excel`, params }) - } -} diff --git a/src/api/erp/sale/out/index.ts b/src/api/erp/sale/out/index.ts deleted file mode 100644 index cbc605e..0000000 --- a/src/api/erp/sale/out/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import request from '@/config/axios' - -// ERP 閿�鍞嚭搴� VO -export interface SaleOutVO { - id: number // 閿�鍞嚭搴撶紪鍙� - no: string // 閿�鍞嚭搴撳彿 - customerId: number // 瀹㈡埛缂栧彿 - outTime: Date // 鍑哄簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 閿�鍞嚭搴� API -export const SaleOutApi = { - // 鏌ヨ閿�鍞嚭搴撳垎椤� - getSaleOutPage: async (params: any) => { - return await request.get({ url: `/erp/sale-out/page`, params }) - }, - - // 鏌ヨ閿�鍞嚭搴撹鎯� - getSaleOut: async (id: number) => { - return await request.get({ url: `/erp/sale-out/get?id=` + id }) - }, - - // 鏂板閿�鍞嚭搴� - createSaleOut: async (data: SaleOutVO) => { - return await request.post({ url: `/erp/sale-out/create`, data }) - }, - - // 淇敼閿�鍞嚭搴� - updateSaleOut: async (data: SaleOutVO) => { - return await request.put({ url: `/erp/sale-out/update`, data }) - }, - - // 鏇存柊閿�鍞嚭搴撶殑鐘舵�� - updateSaleOutStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/sale-out/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閿�鍞嚭搴� - deleteSaleOut: async (ids: number[]) => { - return await request.delete({ - url: `/erp/sale-out/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閿�鍞嚭搴� Excel - exportSaleOut: async (params: any) => { - return await request.download({ url: `/erp/sale-out/export-excel`, params }) - } -} diff --git a/src/api/erp/sale/return/index.ts b/src/api/erp/sale/return/index.ts deleted file mode 100644 index 160ac01..0000000 --- a/src/api/erp/sale/return/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import request from '@/config/axios' - -// ERP 閿�鍞��璐� VO -export interface SaleReturnVO { - id: number // 閿�鍞��璐х紪鍙� - no: string // 閿�鍞��璐у彿 - customerId: number // 瀹㈡埛缂栧彿 - returnTime: Date // 閫�璐ф椂闂� - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 閿�鍞��璐� API -export const SaleReturnApi = { - // 鏌ヨ閿�鍞��璐у垎椤� - getSaleReturnPage: async (params: any) => { - return await request.get({ url: `/erp/sale-return/page`, params }) - }, - - // 鏌ヨ閿�鍞��璐ц鎯� - getSaleReturn: async (id: number) => { - return await request.get({ url: `/erp/sale-return/get?id=` + id }) - }, - - // 鏂板閿�鍞��璐� - createSaleReturn: async (data: SaleReturnVO) => { - return await request.post({ url: `/erp/sale-return/create`, data }) - }, - - // 淇敼閿�鍞��璐� - updateSaleReturn: async (data: SaleReturnVO) => { - return await request.put({ url: `/erp/sale-return/update`, data }) - }, - - // 鏇存柊閿�鍞��璐х殑鐘舵�� - updateSaleReturnStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/sale-return/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎閿�鍞��璐� - deleteSaleReturn: async (ids: number[]) => { - return await request.delete({ - url: `/erp/sale-return/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭閿�鍞��璐� Excel - exportSaleReturn: async (params: any) => { - return await request.download({ url: `/erp/sale-return/export-excel`, params }) - } -} diff --git a/src/api/erp/statistics/purchase/index.ts b/src/api/erp/statistics/purchase/index.ts deleted file mode 100644 index 80d907a..0000000 --- a/src/api/erp/statistics/purchase/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import request from '@/config/axios' - -// ERP 閲囪喘鍏ㄥ眬缁熻 VO -export interface ErpPurchaseSummaryRespVO { - todayPrice: number // 浠婃棩閲囪喘閲戦 - yesterdayPrice: number // 鏄ㄦ棩閲囪喘閲戦 - monthPrice: number // 鏈湀閲囪喘閲戦 - yearPrice: number // 浠婂勾閲囪喘閲戦 -} - -// ERP 閲囪喘鏃堕棿娈电粺璁� VO -export interface ErpPurchaseTimeSummaryRespVO { - time: string // 鏃堕棿 - price: number // 閲囪喘閲戦 -} - -// ERP 閲囪喘缁熻 API -export const PurchaseStatisticsApi = { - // 鑾峰緱閲囪喘缁熻 - getPurchaseSummary: async (): Promise<ErpPurchaseSummaryRespVO> => { - return await request.get({ url: `/erp/purchase-statistics/summary` }) - }, - - // 鑾峰緱閲囪喘鏃堕棿娈电粺璁� - getPurchaseTimeSummary: async (): Promise<ErpPurchaseTimeSummaryRespVO[]> => { - return await request.get({ url: `/erp/purchase-statistics/time-summary` }) - } -} diff --git a/src/api/erp/statistics/sale/index.ts b/src/api/erp/statistics/sale/index.ts deleted file mode 100644 index 09d8500..0000000 --- a/src/api/erp/statistics/sale/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import request from '@/config/axios' - -// ERP 閿�鍞叏灞�缁熻 VO -export interface ErpSaleSummaryRespVO { - todayPrice: number // 浠婃棩閿�鍞噾棰� - yesterdayPrice: number // 鏄ㄦ棩閿�鍞噾棰� - monthPrice: number // 鏈湀閿�鍞噾棰� - yearPrice: number // 浠婂勾閿�鍞噾棰� -} - -// ERP 閿�鍞椂闂存缁熻 VO -export interface ErpSaleTimeSummaryRespVO { - time: string // 鏃堕棿 - price: number // 閿�鍞噾棰� -} - -// ERP 閿�鍞粺璁� API -export const SaleStatisticsApi = { - // 鑾峰緱閿�鍞粺璁� - getSaleSummary: async (): Promise<ErpSaleSummaryRespVO> => { - return await request.get({ url: `/erp/sale-statistics/summary` }) - }, - - // 鑾峰緱閿�鍞椂闂存缁熻 - getSaleTimeSummary: async (): Promise<ErpSaleTimeSummaryRespVO[]> => { - return await request.get({ url: `/erp/sale-statistics/time-summary` }) - } -} diff --git a/src/api/erp/stock/check/index.ts b/src/api/erp/stock/check/index.ts deleted file mode 100644 index 4a3e653..0000000 --- a/src/api/erp/stock/check/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -// ERP 搴撳瓨鐩樼偣鍗� VO -export interface StockCheckVO { - id: number // 鍑哄簱缂栧彿 - no: string // 鍑哄簱鍗曞彿 - outTime: Date // 鍑哄簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 搴撳瓨鐩樼偣鍗� API -export const StockCheckApi = { - // 鏌ヨ搴撳瓨鐩樼偣鍗曞垎椤� - getStockCheckPage: async (params: any) => { - return await request.get({ url: `/erp/stock-check/page`, params }) - }, - - // 鏌ヨ搴撳瓨鐩樼偣鍗曡鎯� - getStockCheck: async (id: number) => { - return await request.get({ url: `/erp/stock-check/get?id=` + id }) - }, - - // 鏂板搴撳瓨鐩樼偣鍗� - createStockCheck: async (data: StockCheckVO) => { - return await request.post({ url: `/erp/stock-check/create`, data }) - }, - - // 淇敼搴撳瓨鐩樼偣鍗� - updateStockCheck: async (data: StockCheckVO) => { - return await request.put({ url: `/erp/stock-check/update`, data }) - }, - - // 鏇存柊搴撳瓨鐩樼偣鍗曠殑鐘舵�� - updateStockCheckStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/stock-check/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎搴撳瓨鐩樼偣鍗� - deleteStockCheck: async (ids: number[]) => { - return await request.delete({ - url: `/erp/stock-check/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭搴撳瓨鐩樼偣鍗� Excel - exportStockCheck: async (params) => { - return await request.download({ url: `/erp/stock-check/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/in/index.ts b/src/api/erp/stock/in/index.ts deleted file mode 100644 index 148b64f..0000000 --- a/src/api/erp/stock/in/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import request from '@/config/axios' - -// ERP 鍏跺畠鍏ュ簱鍗� VO -export interface StockInVO { - id: number // 鍏ュ簱缂栧彿 - no: string // 鍏ュ簱鍗曞彿 - supplierId: number // 渚涘簲鍟嗙紪鍙� - inTime: Date // 鍏ュ簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 鍏跺畠鍏ュ簱鍗� API -export const StockInApi = { - // 鏌ヨ鍏跺畠鍏ュ簱鍗曞垎椤� - getStockInPage: async (params: any) => { - return await request.get({ url: `/erp/stock-in/page`, params }) - }, - - // 鏌ヨ鍏跺畠鍏ュ簱鍗曡鎯� - getStockIn: async (id: number) => { - return await request.get({ url: `/erp/stock-in/get?id=` + id }) - }, - - // 鏂板鍏跺畠鍏ュ簱鍗� - createStockIn: async (data: StockInVO) => { - return await request.post({ url: `/erp/stock-in/create`, data }) - }, - - // 淇敼鍏跺畠鍏ュ簱鍗� - updateStockIn: async (data: StockInVO) => { - return await request.put({ url: `/erp/stock-in/update`, data }) - }, - - // 鏇存柊鍏跺畠鍏ュ簱鍗曠殑鐘舵�� - updateStockInStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/stock-in/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎鍏跺畠鍏ュ簱鍗� - deleteStockIn: async (ids: number[]) => { - return await request.delete({ - url: `/erp/stock-in/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭鍏跺畠鍏ュ簱鍗� Excel - exportStockIn: async (params) => { - return await request.download({ url: `/erp/stock-in/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/move/index.ts b/src/api/erp/stock/move/index.ts deleted file mode 100644 index 398568e..0000000 --- a/src/api/erp/stock/move/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -// ERP 搴撳瓨璋冨害鍗� VO -export interface StockMoveVO { - id: number // 鍑哄簱缂栧彿 - no: string // 鍑哄簱鍗曞彿 - outTime: Date // 鍑哄簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 搴撳瓨璋冨害鍗� API -export const StockMoveApi = { - // 鏌ヨ搴撳瓨璋冨害鍗曞垎椤� - getStockMovePage: async (params: any) => { - return await request.get({ url: `/erp/stock-move/page`, params }) - }, - - // 鏌ヨ搴撳瓨璋冨害鍗曡鎯� - getStockMove: async (id: number) => { - return await request.get({ url: `/erp/stock-move/get?id=` + id }) - }, - - // 鏂板搴撳瓨璋冨害鍗� - createStockMove: async (data: StockMoveVO) => { - return await request.post({ url: `/erp/stock-move/create`, data }) - }, - - // 淇敼搴撳瓨璋冨害鍗� - updateStockMove: async (data: StockMoveVO) => { - return await request.put({ url: `/erp/stock-move/update`, data }) - }, - - // 鏇存柊搴撳瓨璋冨害鍗曠殑鐘舵�� - updateStockMoveStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/stock-move/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎搴撳瓨璋冨害鍗� - deleteStockMove: async (ids: number[]) => { - return await request.delete({ - url: `/erp/stock-move/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭搴撳瓨璋冨害鍗� Excel - exportStockMove: async (params) => { - return await request.download({ url: `/erp/stock-move/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/out/index.ts b/src/api/erp/stock/out/index.ts deleted file mode 100644 index f0f40d3..0000000 --- a/src/api/erp/stock/out/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import request from '@/config/axios' - -// ERP 鍏跺畠鍑哄簱鍗� VO -export interface StockOutVO { - id: number // 鍑哄簱缂栧彿 - no: string // 鍑哄簱鍗曞彿 - customerId: number // 瀹㈡埛缂栧彿 - outTime: Date // 鍑哄簱鏃堕棿 - totalCount: number // 鍚堣鏁伴噺 - totalPrice: number // 鍚堣閲戦锛屽崟浣嶏細鍏� - status: number // 鐘舵�� - remark: string // 澶囨敞 -} - -// ERP 鍏跺畠鍑哄簱鍗� API -export const StockOutApi = { - // 鏌ヨ鍏跺畠鍑哄簱鍗曞垎椤� - getStockOutPage: async (params: any) => { - return await request.get({ url: `/erp/stock-out/page`, params }) - }, - - // 鏌ヨ鍏跺畠鍑哄簱鍗曡鎯� - getStockOut: async (id: number) => { - return await request.get({ url: `/erp/stock-out/get?id=` + id }) - }, - - // 鏂板鍏跺畠鍑哄簱鍗� - createStockOut: async (data: StockOutVO) => { - return await request.post({ url: `/erp/stock-out/create`, data }) - }, - - // 淇敼鍏跺畠鍑哄簱鍗� - updateStockOut: async (data: StockOutVO) => { - return await request.put({ url: `/erp/stock-out/update`, data }) - }, - - // 鏇存柊鍏跺畠鍑哄簱鍗曠殑鐘舵�� - updateStockOutStatus: async (id: number, status: number) => { - return await request.put({ - url: `/erp/stock-out/update-status`, - params: { - id, - status - } - }) - }, - - // 鍒犻櫎鍏跺畠鍑哄簱鍗� - deleteStockOut: async (ids: number[]) => { - return await request.delete({ - url: `/erp/stock-out/delete`, - params: { - ids: ids.join(',') - } - }) - }, - - // 瀵煎嚭鍏跺畠鍑哄簱鍗� Excel - exportStockOut: async (params) => { - return await request.download({ url: `/erp/stock-out/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/record/index.ts b/src/api/erp/stock/record/index.ts deleted file mode 100644 index a758eb4..0000000 --- a/src/api/erp/stock/record/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import request from '@/config/axios' - -// ERP 浜у搧搴撳瓨鏄庣粏 VO -export interface StockRecordVO { - id: number // 缂栧彿 - productId: number // 浜у搧缂栧彿 - warehouseId: number // 浠撳簱缂栧彿 - count: number // 鍑哄叆搴撴暟閲� - totalCount: number // 鎬诲簱瀛橀噺 - bizType: number // 涓氬姟绫诲瀷 - bizId: number // 涓氬姟缂栧彿 - bizItemId: number // 涓氬姟椤圭紪鍙� - bizNo: string // 涓氬姟鍗曞彿 -} - -// ERP 浜у搧搴撳瓨鏄庣粏 API -export const StockRecordApi = { - // 鏌ヨ浜у搧搴撳瓨鏄庣粏鍒嗛〉 - getStockRecordPage: async (params: any) => { - return await request.get({ url: `/erp/stock-record/page`, params }) - }, - - // 鏌ヨ浜у搧搴撳瓨鏄庣粏璇︽儏 - getStockRecord: async (id: number) => { - return await request.get({ url: `/erp/stock-record/get?id=` + id }) - }, - - // 瀵煎嚭浜у搧搴撳瓨鏄庣粏 Excel - exportStockRecord: async (params) => { - return await request.download({ url: `/erp/stock-record/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/stock/index.ts b/src/api/erp/stock/stock/index.ts deleted file mode 100644 index 4de86fb..0000000 --- a/src/api/erp/stock/stock/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import request from '@/config/axios' - -// ERP 浜у搧搴撳瓨 VO -export interface StockVO { - // 缂栧彿 - id: number - // 浜у搧缂栧彿 - productId: number - // 浠撳簱缂栧彿 - warehouseId: number - // 搴撳瓨鏁伴噺 - count: number -} - -// ERP 浜у搧搴撳瓨 API -export const StockApi = { - // 鏌ヨ浜у搧搴撳瓨鍒嗛〉 - getStockPage: async (params: any) => { - return await request.get({ url: `/erp/stock/page`, params }) - }, - - // 鏌ヨ浜у搧搴撳瓨璇︽儏 - getStock: async (id: number) => { - return await request.get({ url: `/erp/stock/get?id=` + id }) - }, - - // 鏌ヨ浜у搧搴撳瓨璇︽儏 - getStock2: async (productId: number, warehouseId: number) => { - return await request.get({ url: `/erp/stock/get`, params: { productId, warehouseId } }) - }, - - // 鑾峰緱浜у搧搴撳瓨鏁伴噺 - getStockCount: async (productId: number) => { - return await request.get({ url: `/erp/stock/get-count`, params: { productId } }) - }, - - // 瀵煎嚭浜у搧搴撳瓨 Excel - exportStock: async (params) => { - return await request.download({ url: `/erp/stock/export-excel`, params }) - } -} diff --git a/src/api/erp/stock/warehouse/index.ts b/src/api/erp/stock/warehouse/index.ts deleted file mode 100644 index 598824b..0000000 --- a/src/api/erp/stock/warehouse/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import request from '@/config/axios' - -// ERP 浠撳簱 VO -export interface WarehouseVO { - id: number // 浠撳簱缂栧彿 - name: string // 浠撳簱鍚嶇О - address: string // 浠撳簱鍦板潃 - sort: number // 鎺掑簭 - remark: string // 澶囨敞 - principal: string // 璐熻矗浜� - warehousePrice: number // 浠撳偍璐癸紝鍗曚綅锛氬厓 - truckagePrice: number // 鎼繍璐癸紝鍗曚綅锛氬厓 - status: number // 寮�鍚姸鎬� - defaultStatus: boolean // 鏄惁榛樿 -} - -// ERP 浠撳簱 API -export const WarehouseApi = { - // 鏌ヨ浠撳簱鍒嗛〉 - getWarehousePage: async (params: any) => { - return await request.get({ url: `/erp/warehouse/page`, params }) - }, - - // 鏌ヨ浠撳簱绮剧畝鍒楄〃 - getWarehouseSimpleList: async () => { - return await request.get({ url: `/erp/warehouse/simple-list` }) - }, - - // 鏌ヨ浠撳簱璇︽儏 - getWarehouse: async (id: number) => { - return await request.get({ url: `/erp/warehouse/get?id=` + id }) - }, - - // 鏂板浠撳簱 - createWarehouse: async (data: WarehouseVO) => { - return await request.post({ url: `/erp/warehouse/create`, data }) - }, - - // 淇敼浠撳簱 - updateWarehouse: async (data: WarehouseVO) => { - return await request.put({ url: `/erp/warehouse/update`, data }) - }, - - // 淇敼浠撳簱榛樿鐘舵�� - updateWarehouseDefaultStatus: async (id: number, defaultStatus: boolean) => { - return await request.put({ - url: `/erp/warehouse/update-default-status`, - params: { - id, - defaultStatus - } - }) - }, - - // 鍒犻櫎浠撳簱 - deleteWarehouse: async (id: number) => { - return await request.delete({ url: `/erp/warehouse/delete?id=` + id }) - }, - - // 瀵煎嚭浠撳簱 Excel - exportWarehouse: async (params) => { - return await request.download({ url: `/erp/warehouse/export-excel`, params }) - } -} diff --git a/src/api/mall/market/banner/index.ts b/src/api/mall/market/banner/index.ts deleted file mode 100644 index ee65024..0000000 --- a/src/api/mall/market/banner/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import request from '@/config/axios' - -export interface BannerVO { - id: number - title: string - picUrl: string - status: number - url: string - position: number - sort: number - memo: string -} - -// 鏌ヨBanner绠$悊鍒楄〃 -export const getBannerPage = async (params) => { - return await request.get({ url: `/promotion/banner/page`, params }) -} - -// 鏌ヨBanner绠$悊璇︽儏 -export const getBanner = async (id: number) => { - return await request.get({ url: `/promotion/banner/get?id=` + id }) -} - -// 鏂板Banner绠$悊 -export const createBanner = async (data: BannerVO) => { - return await request.post({ url: `/promotion/banner/create`, data }) -} - -// 淇敼Banner绠$悊 -export const updateBanner = async (data: BannerVO) => { - return await request.put({ url: `/promotion/banner/update`, data }) -} - -// 鍒犻櫎Banner绠$悊 -export const deleteBanner = async (id: number) => { - return await request.delete({ url: `/promotion/banner/delete?id=` + id }) -} diff --git a/src/api/mall/product/brand.ts b/src/api/mall/product/brand.ts deleted file mode 100644 index 94d5370..0000000 --- a/src/api/mall/product/brand.ts +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/config/axios' - -/** - * 鍟嗗搧鍝佺墝 - */ -export interface BrandVO { - /** - * 鍝佺墝缂栧彿 - */ - id?: number - /** - * 鍝佺墝鍚嶇О - */ - name: string - /** - * 鍝佺墝鍥剧墖 - */ - picUrl: string - /** - * 鍝佺墝鎺掑簭 - */ - sort?: number - /** - * 鍝佺墝鎻忚堪 - */ - description?: string - /** - * 寮�鍚姸鎬� - */ - status: number -} - -// 鍒涘缓鍟嗗搧鍝佺墝 -export const createBrand = (data: BrandVO) => { - return request.post({ url: '/product/brand/create', data }) -} - -// 鏇存柊鍟嗗搧鍝佺墝 -export const updateBrand = (data: BrandVO) => { - return request.put({ url: '/product/brand/update', data }) -} - -// 鍒犻櫎鍟嗗搧鍝佺墝 -export const deleteBrand = (id: number) => { - return request.delete({ url: `/product/brand/delete?id=${id}` }) -} - -// 鑾峰緱鍟嗗搧鍝佺墝 -export const getBrand = (id: number) => { - return request.get({ url: `/product/brand/get?id=${id}` }) -} - -// 鑾峰緱鍟嗗搧鍝佺墝鍒楄〃 -export const getBrandParam = (params: PageParam) => { - return request.get({ url: '/product/brand/page', params }) -} - -// 鑾峰緱鍟嗗搧鍝佺墝绮剧畝淇℃伅鍒楄〃 -export const getSimpleBrandList = () => { - return request.get({ url: '/product/brand/list-all-simple' }) -} diff --git a/src/api/mall/product/category.ts b/src/api/mall/product/category.ts deleted file mode 100644 index 7e80b76..0000000 --- a/src/api/mall/product/category.ts +++ /dev/null @@ -1,56 +0,0 @@ -import request from '@/config/axios' - -/** - * 浜у搧鍒嗙被 - */ -export interface CategoryVO { - /** - * 鍒嗙被缂栧彿 - */ - id?: number - /** - * 鐖跺垎绫荤紪鍙� - */ - parentId?: number - /** - * 鍒嗙被鍚嶇О - */ - name: string - /** - * 绉诲姩绔垎绫诲浘 - */ - picUrl: string - /** - * 鍒嗙被鎺掑簭 - */ - sort: number - /** - * 寮�鍚姸鎬� - */ - status: number -} - -// 鍒涘缓鍟嗗搧鍒嗙被 -export const createCategory = (data: CategoryVO) => { - return request.post({ url: '/product/category/create', data }) -} - -// 鏇存柊鍟嗗搧鍒嗙被 -export const updateCategory = (data: CategoryVO) => { - return request.put({ url: '/product/category/update', data }) -} - -// 鍒犻櫎鍟嗗搧鍒嗙被 -export const deleteCategory = (id: number) => { - return request.delete({ url: `/product/category/delete?id=${id}` }) -} - -// 鑾峰緱鍟嗗搧鍒嗙被 -export const getCategory = (id: number) => { - return request.get({ url: `/product/category/get?id=${id}` }) -} - -// 鑾峰緱鍟嗗搧鍒嗙被鍒楄〃 -export const getCategoryList = (params: any) => { - return request.get({ url: '/product/category/list', params }) -} diff --git a/src/api/mall/product/comment.ts b/src/api/mall/product/comment.ts deleted file mode 100644 index defdbb9..0000000 --- a/src/api/mall/product/comment.ts +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/config/axios' - -export interface CommentVO { - id: number - userId: number - userNickname: string - userAvatar: string - anonymous: boolean - orderId: number - orderItemId: number - spuId: number - spuName: string - skuId: number - visible: boolean - scores: number - descriptionScores: number - benefitScores: number - content: string - picUrls: string - replyStatus: boolean - replyUserId: number - replyContent: string - replyTime: Date -} - -// 鏌ヨ鍟嗗搧璇勮鍒楄〃 -export const getCommentPage = async (params) => { - return await request.get({ url: `/product/comment/page`, params }) -} - -// 鏌ヨ鍟嗗搧璇勮璇︽儏 -export const getComment = async (id: number) => { - return await request.get({ url: `/product/comment/get?id=` + id }) -} - -// 娣诲姞鑷瘎 -export const createComment = async (data: CommentVO) => { - return await request.post({ url: `/product/comment/create`, data }) -} - -// 鏄剧ず / 闅愯棌璇勮 -export const updateCommentVisible = async (data: any) => { - return await request.put({ url: `/product/comment/update-visible`, data }) -} - -// 鍟嗗鍥炲 -export const replyComment = async (data: any) => { - return await request.put({ url: `/product/comment/reply`, data }) -} diff --git a/src/api/mall/product/favorite.ts b/src/api/mall/product/favorite.ts deleted file mode 100644 index 3834eed..0000000 --- a/src/api/mall/product/favorite.ts +++ /dev/null @@ -1,12 +0,0 @@ -import request from '@/config/axios' - -export interface Favorite { - id?: number - userId?: string // 鐢ㄦ埛缂栧彿 - spuId?: number | null // 鍟嗗搧 SPU 缂栧彿 -} - -// 鑾峰緱 ProductFavorite 鍒楄〃 -export const getFavoritePage = (params: PageParam) => { - return request.get({ url: '/product/favorite/page', params }) -} diff --git a/src/api/mall/product/history.ts b/src/api/mall/product/history.ts deleted file mode 100644 index 0aa45bd..0000000 --- a/src/api/mall/product/history.ts +++ /dev/null @@ -1,10 +0,0 @@ -import request from '@/config/axios' - -/** - * 鑾峰緱鍟嗗搧娴忚璁板綍鍒嗛〉 - * - * @param params 璇锋眰鍙傛暟 - */ -export const getBrowseHistoryPage = (params: any) => { - return request.get({ url: '/product/browse-history/page', params }) -} diff --git a/src/api/mall/product/property.ts b/src/api/mall/product/property.ts deleted file mode 100644 index 44dc663..0000000 --- a/src/api/mall/product/property.ts +++ /dev/null @@ -1,93 +0,0 @@ -import request from '@/config/axios' - -/** - * 鍟嗗搧灞炴�� - */ -export interface PropertyVO { - id?: number - /** 鍚嶇О */ - name: string - /** 澶囨敞 */ - remark?: string -} - -/** - * 灞炴�у�� - */ -export interface PropertyValueVO { - id?: number - /** 灞炴�ч」鐨勭紪鍙� */ - propertyId?: number - /** 鍚嶇О */ - name: string - /** 澶囨敞 */ - remark?: string -} - -/** - * 鍟嗗搧灞炴�у�肩殑鏄庣粏 - */ -export interface PropertyValueDetailVO { - /** 灞炴�ч」鐨勭紪鍙� */ - propertyId: number // 灞炴�х殑缂栧彿 - /** 灞炴�х殑鍚嶇О */ - propertyName: string - /** 灞炴�у�肩殑缂栧彿 */ - valueId: number - /** 灞炴�у�肩殑鍚嶇О */ - valueName: string -} - -// ------------------------ 灞炴�ч」 ------------------- - -// 鍒涘缓灞炴�ч」 -export const createProperty = (data: PropertyVO) => { - return request.post({ url: '/product/property/create', data }) -} - -// 鏇存柊灞炴�ч」 -export const updateProperty = (data: PropertyVO) => { - return request.put({ url: '/product/property/update', data }) -} - -// 鍒犻櫎灞炴�ч」 -export const deleteProperty = (id: number) => { - return request.delete({ url: `/product/property/delete?id=${id}` }) -} - -// 鑾峰緱灞炴�ч」 -export const getProperty = (id: number): Promise<PropertyVO> => { - return request.get({ url: `/product/property/get?id=${id}` }) -} - -// 鑾峰緱灞炴�ч」鍒嗛〉 -export const getPropertyPage = (params: PageParam) => { - return request.get({ url: '/product/property/page', params }) -} - -// ------------------------ 灞炴�у�� ------------------- - -// 鑾峰緱灞炴�у�煎垎椤� -export const getPropertyValuePage = (params: PageParam & any) => { - return request.get({ url: '/product/property/value/page', params }) -} - -// 鑾峰緱灞炴�у�� -export const getPropertyValue = (id: number): Promise<PropertyValueVO> => { - return request.get({ url: `/product/property/value/get?id=${id}` }) -} - -// 鍒涘缓灞炴�у�� -export const createPropertyValue = (data: PropertyValueVO) => { - return request.post({ url: '/product/property/value/create', data }) -} - -// 鏇存柊灞炴�у�� -export const updatePropertyValue = (data: PropertyValueVO) => { - return request.put({ url: '/product/property/value/update', data }) -} - -// 鍒犻櫎灞炴�у�� -export const deletePropertyValue = (id: number) => { - return request.delete({ url: `/product/property/value/delete?id=${id}` }) -} diff --git a/src/api/mall/product/spu.ts b/src/api/mall/product/spu.ts deleted file mode 100644 index eee632d..0000000 --- a/src/api/mall/product/spu.ts +++ /dev/null @@ -1,109 +0,0 @@ -import request from '@/config/axios' - -export interface Property { - propertyId?: number // 灞炴�х紪鍙� - propertyName?: string // 灞炴�у悕绉� - valueId?: number // 灞炴�у�肩紪鍙� - valueName?: string // 灞炴�у�煎悕绉� -} - -export interface Sku { - id?: number // 鍟嗗搧 SKU 缂栧彿 - name?: string // 鍟嗗搧 SKU 鍚嶇О - spuId?: number // SPU 缂栧彿 - properties?: Property[] // 灞炴�ф暟缁� - price?: number | string // 鍟嗗搧浠锋牸 - marketPrice?: number | string // 甯傚満浠� - costPrice?: number | string // 鎴愭湰浠� - barCode?: string // 鍟嗗搧鏉$爜 - picUrl?: string // 鍥剧墖鍦板潃 - stock?: number // 搴撳瓨 - weight?: number // 鍟嗗搧閲嶉噺锛屽崟浣嶏細kg 鍗冨厠 - volume?: number // 鍟嗗搧浣撶Н锛屽崟浣嶏細m^3 骞崇背 - firstBrokeragePrice?: number | string // 涓�绾у垎閿�鐨勪剑閲� - secondBrokeragePrice?: number | string // 浜岀骇鍒嗛攢鐨勪剑閲� - salesCount?: number // 鍟嗗搧閿�閲� -} - -export interface GiveCouponTemplate { - id?: number - name?: string // 浼樻儬鍒稿悕绉� -} - -export interface Spu { - id?: number - name?: string // 鍟嗗搧鍚嶇О - categoryId?: number // 鍟嗗搧鍒嗙被 - keyword?: string // 鍏抽敭瀛� - unit?: number | undefined // 鍗曚綅 - picUrl?: string // 鍟嗗搧灏侀潰鍥� - sliderPicUrls?: string[] // 鍟嗗搧杞挱鍥� - introduction?: string // 鍟嗗搧绠�浠� - deliveryTypes?: number[] // 閰嶉�佹柟寮� - deliveryTemplateId?: number | undefined // 杩愯垂妯$増 - brandId?: number // 鍟嗗搧鍝佺墝缂栧彿 - specType?: boolean // 鍟嗗搧瑙勬牸 - subCommissionType?: boolean // 鍒嗛攢绫诲瀷 - skus?: Sku[] // sku鏁扮粍 - description?: string // 鍟嗗搧璇︽儏 - sort?: number // 鍟嗗搧鎺掑簭 - giveIntegral?: number // 璧犻�佺Н鍒� - virtualSalesCount?: number // 铏氭嫙閿�閲� - price?: number // 鍟嗗搧浠锋牸 - salesCount?: number // 鍟嗗搧閿�閲� - marketPrice?: number // 甯傚満浠� - costPrice?: number // 鎴愭湰浠� - stock?: number // 鍟嗗搧搴撳瓨 - createTime?: Date // 鍟嗗搧鍒涘缓鏃堕棿 - status?: number // 鍟嗗搧鐘舵�� -} - -// 鑾峰緱 Spu 鍒楄〃 -export const getSpuPage = (params: PageParam) => { - return request.get({ url: '/product/spu/page', params }) -} - -// 鑾峰緱 Spu 鍒楄〃 tabsCount -export const getTabsCount = () => { - return request.get({ url: '/product/spu/get-count' }) -} - -// 鍒涘缓鍟嗗搧 Spu -export const createSpu = (data: Spu) => { - return request.post({ url: '/product/spu/create', data }) -} - -// 鏇存柊鍟嗗搧 Spu -export const updateSpu = (data: Spu) => { - return request.put({ url: '/product/spu/update', data }) -} - -// 鏇存柊鍟嗗搧 Spu status -export const updateStatus = (data: { id: number; status: number }) => { - return request.put({ url: '/product/spu/update-status', data }) -} - -// 鑾峰緱鍟嗗搧 Spu -export const getSpu = (id: number) => { - return request.get({ url: `/product/spu/get-detail?id=${id}` }) -} - -// 鑾峰緱鍟嗗搧 Spu 璇︽儏鍒楄〃 -export const getSpuDetailList = (ids: number[]) => { - return request.get({ url: `/product/spu/list?spuIds=${ids}` }) -} - -// 鍒犻櫎鍟嗗搧 Spu -export const deleteSpu = (id: number) => { - return request.delete({ url: `/product/spu/delete?id=${id}` }) -} - -// 瀵煎嚭鍟嗗搧 Spu Excel -export const exportSpu = async (params) => { - return await request.download({ url: '/product/spu/export', params }) -} - -// 鑾峰緱鍟嗗搧 SPU 绮剧畝鍒楄〃 -export const getSpuSimpleList = async () => { - return request.get({ url: '/product/spu/list-all-simple' }) -} diff --git a/src/api/mall/promotion/article/index.ts b/src/api/mall/promotion/article/index.ts deleted file mode 100644 index 9184c7a..0000000 --- a/src/api/mall/promotion/article/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import request from '@/config/axios' - -export interface ArticleVO { - id: number - categoryId: number - title: string - author: string - picUrl: string - introduction: string - browseCount: string - sort: number - status: number - spuId: number - recommendHot: boolean - recommendBanner: boolean - content: string -} - -// 鏌ヨ鏂囩珷绠$悊鍒楄〃 -export const getArticlePage = async (params: any) => { - return await request.get({ url: `/promotion/article/page`, params }) -} - -// 鏌ヨ鏂囩珷绠$悊璇︽儏 -export const getArticle = async (id: number) => { - return await request.get({ url: `/promotion/article/get?id=` + id }) -} - -// 鏂板鏂囩珷绠$悊 -export const createArticle = async (data: ArticleVO) => { - return await request.post({ url: `/promotion/article/create`, data }) -} - -// 淇敼鏂囩珷绠$悊 -export const updateArticle = async (data: ArticleVO) => { - return await request.put({ url: `/promotion/article/update`, data }) -} - -// 鍒犻櫎鏂囩珷绠$悊 -export const deleteArticle = async (id: number) => { - return await request.delete({ url: `/promotion/article/delete?id=` + id }) -} diff --git a/src/api/mall/promotion/articleCategory/index.ts b/src/api/mall/promotion/articleCategory/index.ts deleted file mode 100644 index 47f5e93..0000000 --- a/src/api/mall/promotion/articleCategory/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import request from '@/config/axios' - -export interface ArticleCategoryVO { - id: number - name: string - picUrl: string - status: number - sort: number -} - -// 鏌ヨ鏂囩珷鍒嗙被鍒楄〃 -export const getArticleCategoryPage = async (params) => { - return await request.get({ url: `/promotion/article-category/page`, params }) -} - -// 鏌ヨ鏂囩珷鍒嗙被绮剧畝淇℃伅鍒楄〃 -export const getSimpleArticleCategoryList = async () => { - return await request.get({ url: `/promotion/article-category/list-all-simple` }) -} - -// 鏌ヨ鏂囩珷鍒嗙被璇︽儏 -export const getArticleCategory = async (id: number) => { - return await request.get({ url: `/promotion/article-category/get?id=` + id }) -} - -// 鏂板鏂囩珷鍒嗙被 -export const createArticleCategory = async (data: ArticleCategoryVO) => { - return await request.post({ url: `/promotion/article-category/create`, data }) -} - -// 淇敼鏂囩珷鍒嗙被 -export const updateArticleCategory = async (data: ArticleCategoryVO) => { - return await request.put({ url: `/promotion/article-category/update`, data }) -} - -// 鍒犻櫎鏂囩珷鍒嗙被 -export const deleteArticleCategory = async (id: number) => { - return await request.delete({ url: `/promotion/article-category/delete?id=` + id }) -} diff --git a/src/api/mall/promotion/bargain/bargainActivity.ts b/src/api/mall/promotion/bargain/bargainActivity.ts deleted file mode 100644 index 9ad219a..0000000 --- a/src/api/mall/promotion/bargain/bargainActivity.ts +++ /dev/null @@ -1,68 +0,0 @@ -import request from '@/config/axios' -import { Sku, Spu } from '@/api/mall/product/spu' - -export interface BargainActivityVO { - id?: number - name?: string - startTime?: Date - endTime?: Date - status?: number - helpMaxCount?: number // 杈惧埌璇ヤ汉鏁帮紝鎵嶈兘鐮嶅埌浣庝环 - bargainCount?: number // 鏈�澶у府鐮嶆鏁� - totalLimitCount?: number // 鏈�澶ц喘涔版鏁� - spuId: number - skuId: number - bargainFirstPrice: number // 鐮嶄环璧峰浠锋牸锛屽崟浣嶅垎 - bargainMinPrice: number // 鐮嶄环搴曚环 - stock: number // 娲诲姩搴撳瓨 - randomMinPrice?: number // 鐢ㄦ埛姣忔鐮嶄环鐨勬渶灏忛噾棰濓紝鍗曚綅锛氬垎 - randomMaxPrice?: number // 鐢ㄦ埛姣忔鐮嶄环鐨勬渶澶ч噾棰濓紝鍗曚綅锛氬垎 -} - -// 鐮嶄环娲诲姩鎵�闇�灞炴�с�傞�夋嫨鐨勫晢鍝佸拰灞炴�х殑鏃跺�欎娇鐢ㄦ柟渚夸娇鐢ㄦ椿鍔ㄧ殑閫氱敤灏佽 -export interface BargainProductVO { - spuId: number - skuId: number - bargainFirstPrice: number // 鐮嶄环璧峰浠锋牸锛屽崟浣嶅垎 - bargainMinPrice: number // 鐮嶄环搴曚环 - stock: number // 娲诲姩搴撳瓨 -} - -// 鎵╁睍 Sku 閰嶇疆 -export type SkuExtension = Sku & { - productConfig: BargainProductVO -} - -export interface SpuExtension extends Spu { - skus: SkuExtension[] // 閲嶅啓绫诲瀷 -} - -// 鏌ヨ鐮嶄环娲诲姩鍒楄〃 -export const getBargainActivityPage = async (params: any) => { - return await request.get({ url: '/promotion/bargain-activity/page', params }) -} - -// 鏌ヨ鐮嶄环娲诲姩璇︽儏 -export const getBargainActivity = async (id: number) => { - return await request.get({ url: '/promotion/bargain-activity/get?id=' + id }) -} - -// 鏂板鐮嶄环娲诲姩 -export const createBargainActivity = async (data: BargainActivityVO) => { - return await request.post({ url: '/promotion/bargain-activity/create', data }) -} - -// 淇敼鐮嶄环娲诲姩 -export const updateBargainActivity = async (data: BargainActivityVO) => { - return await request.put({ url: '/promotion/bargain-activity/update', data }) -} - -// 鍏抽棴鐮嶄环娲诲姩 -export const closeBargainActivity = async (id: number) => { - return await request.put({ url: '/promotion/bargain-activity/close?id=' + id }) -} - -// 鍒犻櫎鐮嶄环娲诲姩 -export const deleteBargainActivity = async (id: number) => { - return await request.delete({ url: '/promotion/bargain-activity/delete?id=' + id }) -} diff --git a/src/api/mall/promotion/bargain/bargainHelp.ts b/src/api/mall/promotion/bargain/bargainHelp.ts deleted file mode 100644 index 4308ae6..0000000 --- a/src/api/mall/promotion/bargain/bargainHelp.ts +++ /dev/null @@ -1,14 +0,0 @@ -import request from '@/config/axios' - -export interface BargainHelpVO { - id: number - record: number - userId: number - reducePrice: number - endTime: Date -} - -// 鏌ヨ鐮嶄环璁板綍鍒楄〃 -export const getBargainHelpPage = async (params) => { - return await request.get({ url: `/promotion/bargain-help/page`, params }) -} diff --git a/src/api/mall/promotion/bargain/bargainRecord.ts b/src/api/mall/promotion/bargain/bargainRecord.ts deleted file mode 100644 index f90b784..0000000 --- a/src/api/mall/promotion/bargain/bargainRecord.ts +++ /dev/null @@ -1,19 +0,0 @@ -import request from '@/config/axios' - -export interface BargainRecordVO { - id: number - activityId: number - userId: number - spuId: number - skuId: number - bargainFirstPrice: number - bargainPrice: number - status: number - orderId: number - endTime: Date -} - -// 鏌ヨ鐮嶄环璁板綍鍒楄〃 -export const getBargainRecordPage = async (params) => { - return await request.get({ url: `/promotion/bargain-record/page`, params }) -} diff --git a/src/api/mall/promotion/combination/combinationActivity.ts b/src/api/mall/promotion/combination/combinationActivity.ts deleted file mode 100644 index 062db5c..0000000 --- a/src/api/mall/promotion/combination/combinationActivity.ts +++ /dev/null @@ -1,66 +0,0 @@ -import request from '@/config/axios' -import { Sku, Spu } from '@/api/mall/product/spu' - -export interface CombinationActivityVO { - id?: number - name?: string - spuId?: number - totalLimitCount?: number - singleLimitCount?: number - startTime?: Date - endTime?: Date - userSize?: number - totalCount?: number - successCount?: number - orderUserCount?: number - virtualGroup?: number - status?: number - limitDuration?: number - products: CombinationProductVO[] -} - -// 鎷煎洟娲诲姩鎵�闇�灞炴�� -export interface CombinationProductVO { - spuId: number - skuId: number - combinationPrice: number // 鎷煎洟浠锋牸 -} - -// 鎵╁睍 Sku 閰嶇疆 -export type SkuExtension = Sku & { - productConfig: CombinationProductVO -} - -export interface SpuExtension extends Spu { - skus: SkuExtension[] // 閲嶅啓绫诲瀷 -} - -// 鏌ヨ鎷煎洟娲诲姩鍒楄〃 -export const getCombinationActivityPage = async (params) => { - return await request.get({ url: '/promotion/combination-activity/page', params }) -} - -// 鏌ヨ鎷煎洟娲诲姩璇︽儏 -export const getCombinationActivity = async (id: number) => { - return await request.get({ url: '/promotion/combination-activity/get?id=' + id }) -} - -// 鏂板鎷煎洟娲诲姩 -export const createCombinationActivity = async (data: CombinationActivityVO) => { - return await request.post({ url: '/promotion/combination-activity/create', data }) -} - -// 淇敼鎷煎洟娲诲姩 -export const updateCombinationActivity = async (data: CombinationActivityVO) => { - return await request.put({ url: '/promotion/combination-activity/update', data }) -} - -// 鍏抽棴鎷煎洟娲诲姩 -export const closeCombinationActivity = async (id: number) => { - return await request.put({ url: '/promotion/combination-activity/close?id=' + id }) -} - -// 鍒犻櫎鎷煎洟娲诲姩 -export const deleteCombinationActivity = async (id: number) => { - return await request.delete({ url: '/promotion/combination-activity/delete?id=' + id }) -} diff --git a/src/api/mall/promotion/combination/combinationRecord.ts b/src/api/mall/promotion/combination/combinationRecord.ts deleted file mode 100644 index b2b7d75..0000000 --- a/src/api/mall/promotion/combination/combinationRecord.ts +++ /dev/null @@ -1,28 +0,0 @@ -import request from '@/config/axios' - -export interface CombinationRecordVO { - id: number // 鎷煎洟璁板綍缂栧彿 - activityId: number // 鎷煎洟娲诲姩缂栧彿 - nickname: string // 鐢ㄦ埛鏄电О - avatar: string // 鐢ㄦ埛澶村儚 - headId: number // 鍥㈤暱缂栧彿 - expireTime: string // 杩囨湡鏃堕棿 - userSize: number // 鍙弬鍥汉鏁� - userCount: number // 宸插弬鍥汉鏁� - status: number // 鎷煎洟鐘舵�� - spuName: string // 鍟嗗搧鍚嶅瓧 - picUrl: string // 鍟嗗搧鍥剧墖 - virtualGroup: boolean // 鏄惁铏氭嫙鎴愬洟 - startTime: string // 寮�濮嬫椂闂� (璁㈠崟浠樻鍚庡紑濮嬬殑鏃堕棿) - endTime: string // 缁撴潫鏃堕棿锛堟垚鍥㈡椂闂�/澶辫触鏃堕棿锛� -} - -// 鏌ヨ鎷煎洟璁板綍鍒楄〃 -export const getCombinationRecordPage = async (params: any) => { - return await request.get({ url: '/promotion/combination-record/page', params }) -} - -// 鑾峰緱鎷煎洟璁板綍鐨勬瑕佷俊鎭� -export const getCombinationRecordSummary = async () => { - return await request.get({ url: '/promotion/combination-record/get-summary' }) -} diff --git a/src/api/mall/promotion/coupon/coupon.ts b/src/api/mall/promotion/coupon/coupon.ts deleted file mode 100755 index 2ebff5d..0000000 --- a/src/api/mall/promotion/coupon/coupon.ts +++ /dev/null @@ -1,26 +0,0 @@ -import request from '@/config/axios' - -// TODO @dhb52锛歷o 缂哄皯 - -// 鍒犻櫎浼樻儬鍔� -export const deleteCoupon = async (id: number) => { - return request.delete({ - url: `/promotion/coupon/delete?id=${id}` - }) -} - -// 鑾峰緱浼樻儬鍔靛垎椤� -export const getCouponPage = async (params: PageParam) => { - return request.get({ - url: '/promotion/coupon/page', - params: params - }) -} - -// 鍙戦�佷紭鎯犲埜 -export const sendCoupon = async (data: any) => { - return request.post({ - url: '/promotion/coupon/send', - data: data - }) -} diff --git a/src/api/mall/promotion/coupon/couponTemplate.ts b/src/api/mall/promotion/coupon/couponTemplate.ts deleted file mode 100755 index 50ae226..0000000 --- a/src/api/mall/promotion/coupon/couponTemplate.ts +++ /dev/null @@ -1,90 +0,0 @@ -import request from '@/config/axios' - -export interface CouponTemplateVO { - id: number - name: string - status: number - totalCount: number - takeLimitCount: number - takeType: number - usePrice: number - productScope: number - productScopeValues: number[] - validityType: number - validStartTime: Date - validEndTime: Date - fixedStartTerm: number - fixedEndTerm: number - discountType: number - discountPercent: number - discountPrice: number - discountLimitPrice: number - takeCount: number - useCount: number -} - -// 鍒涘缓浼樻儬鍔垫ā鏉� -export function createCouponTemplate(data: CouponTemplateVO) { - return request.post({ - url: '/promotion/coupon-template/create', - data: data - }) -} - -// 鏇存柊浼樻儬鍔垫ā鏉� -export function updateCouponTemplate(data: CouponTemplateVO) { - return request.put({ - url: '/promotion/coupon-template/update', - data: data - }) -} - -// 鏇存柊浼樻儬鍔垫ā鏉跨殑鐘舵�� -export function updateCouponTemplateStatus(id: number, status: [0, 1]) { - const data = { - id, - status - } - return request.put({ - url: '/promotion/coupon-template/update-status', - data: data - }) -} - -// 鍒犻櫎浼樻儬鍔垫ā鏉� -export function deleteCouponTemplate(id: number) { - return request.delete({ - url: '/promotion/coupon-template/delete?id=' + id - }) -} - -// 鑾峰緱浼樻儬鍔垫ā鏉� -export function getCouponTemplate(id: number) { - return request.get({ - url: '/promotion/coupon-template/get?id=' + id - }) -} - -// 鑾峰緱浼樻儬鍔垫ā鏉垮垎椤� -export function getCouponTemplatePage(params: PageParam) { - return request.get({ - url: '/promotion/coupon-template/page', - params: params - }) -} - -// 鑾峰緱浼樻儬鍔垫ā鏉垮垎椤� -export function getCouponTemplateList(ids: number[]) { - return request.get({ - url: `/promotion/coupon-template/list?ids=${ids}` - }) -} - -// 瀵煎嚭浼樻儬鍔垫ā鏉� Excel -export function exportCouponTemplateExcel(params: PageParam) { - return request.get({ - url: '/promotion/coupon-template/export-excel', - params: params, - responseType: 'blob' - }) -} diff --git a/src/api/mall/promotion/discount/discountActivity.ts b/src/api/mall/promotion/discount/discountActivity.ts deleted file mode 100644 index e755c1b..0000000 --- a/src/api/mall/promotion/discount/discountActivity.ts +++ /dev/null @@ -1,60 +0,0 @@ -import request from '@/config/axios' -import { Sku, Spu } from '@/api/mall/product/spu' - -export interface DiscountActivityVO { - id?: number - spuId?: number - name?: string - status?: number - remark?: string - startTime?: Date - endTime?: Date - products?: DiscountProductVO[] -} -// 闄愭椂鎶樻墸鐩稿叧 灞炴�� -export interface DiscountProductVO { - spuId: number - skuId: number - discountType: number - discountPercent: number - discountPrice: number -} - -// 鎵╁睍 Sku 閰嶇疆 -export type SkuExtension = Sku & { - productConfig: DiscountProductVO -} - -export interface SpuExtension extends Spu { - skus: SkuExtension[] // 閲嶅啓绫诲瀷 -} - -// 鏌ヨ闄愭椂鎶樻墸娲诲姩鍒楄〃 -export const getDiscountActivityPage = async (params) => { - return await request.get({ url: '/promotion/discount-activity/page', params }) -} - -// 鏌ヨ闄愭椂鎶樻墸娲诲姩璇︽儏 -export const getDiscountActivity = async (id: number) => { - return await request.get({ url: '/promotion/discount-activity/get?id=' + id }) -} - -// 鏂板闄愭椂鎶樻墸娲诲姩 -export const createDiscountActivity = async (data: DiscountActivityVO) => { - return await request.post({ url: '/promotion/discount-activity/create', data }) -} - -// 淇敼闄愭椂鎶樻墸娲诲姩 -export const updateDiscountActivity = async (data: DiscountActivityVO) => { - return await request.put({ url: '/promotion/discount-activity/update', data }) -} - -// 鍏抽棴闄愭椂鎶樻墸娲诲姩 -export const closeDiscountActivity = async (id: number) => { - return await request.put({ url: '/promotion/discount-activity/close?id=' + id }) -} - -// 鍒犻櫎闄愭椂鎶樻墸娲诲姩 -export const deleteDiscountActivity = async (id: number) => { - return await request.delete({ url: '/promotion/discount-activity/delete?id=' + id }) -} diff --git a/src/api/mall/promotion/diy/page.ts b/src/api/mall/promotion/diy/page.ts deleted file mode 100644 index a834b24..0000000 --- a/src/api/mall/promotion/diy/page.ts +++ /dev/null @@ -1,45 +0,0 @@ -import request from '@/config/axios' - -export interface DiyPageVO { - id?: number - templateId?: number - name: string - remark: string - previewPicUrls: string[] - property: string -} - -// 鏌ヨ瑁呬慨椤甸潰鍒楄〃 -export const getDiyPagePage = async (params: any) => { - return await request.get({ url: `/promotion/diy-page/page`, params }) -} - -// 鏌ヨ瑁呬慨椤甸潰璇︽儏 -export const getDiyPage = async (id: number) => { - return await request.get({ url: `/promotion/diy-page/get?id=` + id }) -} - -// 鏂板瑁呬慨椤甸潰 -export const createDiyPage = async (data: DiyPageVO) => { - return await request.post({ url: `/promotion/diy-page/create`, data }) -} - -// 淇敼瑁呬慨椤甸潰 -export const updateDiyPage = async (data: DiyPageVO) => { - return await request.put({ url: `/promotion/diy-page/update`, data }) -} - -// 鍒犻櫎瑁呬慨椤甸潰 -export const deleteDiyPage = async (id: number) => { - return await request.delete({ url: `/promotion/diy-page/delete?id=` + id }) -} - -// 鑾峰緱瑁呬慨椤甸潰灞炴�� -export const getDiyPageProperty = async (id: number) => { - return await request.get({ url: `/promotion/diy-page/get-property?id=` + id }) -} - -// 鏇存柊瑁呬慨椤甸潰灞炴�� -export const updateDiyPageProperty = async (data: DiyPageVO) => { - return await request.put({ url: `/promotion/diy-page/update-property`, data }) -} diff --git a/src/api/mall/promotion/diy/template.ts b/src/api/mall/promotion/diy/template.ts deleted file mode 100644 index 87134c9..0000000 --- a/src/api/mall/promotion/diy/template.ts +++ /dev/null @@ -1,58 +0,0 @@ -import request from '@/config/axios' -import { DiyPageVO } from '@/api/mall/promotion/diy/page' - -export interface DiyTemplateVO { - id?: number - name: string - used: boolean - usedTime?: Date - remark: string - previewPicUrls: string[] - property: string -} - -export interface DiyTemplatePropertyVO extends DiyTemplateVO { - pages: DiyPageVO[] -} - -// 鏌ヨ瑁呬慨妯℃澘鍒楄〃 -export const getDiyTemplatePage = async (params: any) => { - return await request.get({ url: `/promotion/diy-template/page`, params }) -} - -// 鏌ヨ瑁呬慨妯℃澘璇︽儏 -export const getDiyTemplate = async (id: number) => { - return await request.get({ url: `/promotion/diy-template/get?id=` + id }) -} - -// 鏂板瑁呬慨妯℃澘 -export const createDiyTemplate = async (data: DiyTemplateVO) => { - return await request.post({ url: `/promotion/diy-template/create`, data }) -} - -// 淇敼瑁呬慨妯℃澘 -export const updateDiyTemplate = async (data: DiyTemplateVO) => { - return await request.put({ url: `/promotion/diy-template/update`, data }) -} - -// 鍒犻櫎瑁呬慨妯℃澘 -export const deleteDiyTemplate = async (id: number) => { - return await request.delete({ url: `/promotion/diy-template/delete?id=` + id }) -} - -// 浣跨敤瑁呬慨妯℃澘 -export const useDiyTemplate = async (id: number) => { - return await request.put({ url: `/promotion/diy-template/use?id=` + id }) -} - -// 鑾峰緱瑁呬慨妯℃澘灞炴�� -export const getDiyTemplateProperty = async (id: number) => { - return await request.get<DiyTemplatePropertyVO>({ - url: `/promotion/diy-template/get-property?id=` + id - }) -} - -// 鏇存柊瑁呬慨妯℃澘灞炴�� -export const updateDiyTemplateProperty = async (data: DiyTemplateVO) => { - return await request.put({ url: `/promotion/diy-template/update-property`, data }) -} diff --git a/src/api/mall/promotion/kefu/conversation/index.ts b/src/api/mall/promotion/kefu/conversation/index.ts deleted file mode 100644 index 2dbf331..0000000 --- a/src/api/mall/promotion/kefu/conversation/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import request from '@/config/axios' - -export interface KeFuConversationRespVO { - id: number // 缂栧彿 - userId: number // 浼氳瘽鎵�灞炵敤鎴� - userAvatar: string // 浼氳瘽鎵�灞炵敤鎴峰ご鍍� - userNickname: string // 浼氳瘽鎵�灞炵敤鎴锋樀绉� - lastMessageTime: Date // 鏈�鍚庤亰澶╂椂闂� - lastMessageContent: string // 鏈�鍚庤亰澶╁唴瀹� - lastMessageContentType: number // 鏈�鍚庡彂閫佺殑娑堟伅绫诲瀷 - adminPinned: boolean // 绠$悊绔疆椤� - userDeleted: boolean // 鐢ㄦ埛鏄惁鍙 - adminDeleted: boolean // 绠$悊鍛樻槸鍚﹀彲瑙� - adminUnreadMessageCount: number // 绠$悊鍛樻湭璇绘秷鎭暟 - createTime?: string // 鍒涘缓鏃堕棿 -} - -// 瀹㈡湇浼氳瘽 API -export const KeFuConversationApi = { - // 鑾峰緱瀹㈡湇浼氳瘽鍒楄〃 - getConversationList: async () => { - return await request.get({ url: '/promotion/kefu-conversation/list' }) - }, - // 瀹㈡湇浼氳瘽缃《 - updateConversationPinned: async (data: any) => { - return await request.put({ - url: '/promotion/kefu-conversation/update-conversation-pinned', - data - }) - }, - // 鍒犻櫎瀹㈡湇浼氳瘽 - deleteConversation: async (id: number) => { - return await request.get({ url: '/promotion/kefu-conversation/delete?id' + id }) - } -} diff --git a/src/api/mall/promotion/kefu/message/index.ts b/src/api/mall/promotion/kefu/message/index.ts deleted file mode 100644 index a12167f..0000000 --- a/src/api/mall/promotion/kefu/message/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import request from '@/config/axios' - -export interface KeFuMessageRespVO { - id: number // 缂栧彿 - conversationId: number // 浼氳瘽缂栧彿 - senderId: number // 鍙戦�佷汉缂栧彿 - senderAvatar: string // 鍙戦�佷汉澶村儚 - senderType: number // 鍙戦�佷汉绫诲瀷 - receiverId: number // 鎺ユ敹浜虹紪鍙� - receiverType: number // 鎺ユ敹浜虹被鍨� - contentType: number // 娑堟伅绫诲瀷 - content: string // 娑堟伅 - readStatus: boolean // 鏄惁宸茶 - createTime: Date // 鍒涘缓鏃堕棿 -} - -// 瀹㈡湇浼氳瘽 API -export const KeFuMessageApi = { - // 鍙戦�佸鏈嶆秷鎭� - sendKeFuMessage: async (data: any) => { - return await request.post({ - url: '/promotion/kefu-message/send', - data - }) - }, - // 鏇存柊瀹㈡湇娑堟伅宸茶鐘舵�� - updateKeFuMessageReadStatus: async (conversationId: number) => { - return await request.put({ - url: '/promotion/kefu-message/update-read-status?conversationId=' + conversationId - }) - }, - // 鑾峰緱娑堟伅鍒嗛〉鏁版嵁 - getKeFuMessagePage: async (params: any) => { - return await request.get({ url: '/promotion/kefu-message/page', params }) - } -} diff --git a/src/api/mall/promotion/reward/rewardActivity.ts b/src/api/mall/promotion/reward/rewardActivity.ts deleted file mode 100644 index 691db47..0000000 --- a/src/api/mall/promotion/reward/rewardActivity.ts +++ /dev/null @@ -1,48 +0,0 @@ -import request from '@/config/axios' - -export interface DiscountActivityVO { - id?: number - name?: string - startTime?: Date - endTime?: Date - remark?: string - conditionType?: number - productScope?: number - productSpuIds?: number[] - rules?: DiscountProductVO[] -} - -// 浼樻儬瑙勫垯 -export interface DiscountProductVO { - limit: number - discountPrice: number - freeDelivery: boolean - point: number - couponIds: number[] - couponCounts: number[] -} - -// 鏂板婊″噺閫佹椿鍔� -export const createRewardActivity = async (data: DiscountActivityVO) => { - return await request.post({ url: '/promotion/reward-activity/create', data }) -} - -// 鏇存柊婊″噺閫佹椿鍔� -export const updateRewardActivity = async (data: DiscountActivityVO) => { - return await request.put({ url: '/promotion/reward-activity/update', data }) -} - -// 鏌ヨ婊″噺閫佹椿鍔ㄥ垪琛� -export const getRewardActivityPage = async (params) => { - return await request.get({ url: '/promotion/reward-activity/page', params }) -} - -// 鏌ヨ婊″噺閫佹椿鍔ㄨ鎯� -export const getReward = async (id: number) => { - return await request.get({ url: '/promotion/reward-activity/get?id=' + id }) -} - -// 鍒犻櫎闄愭椂鎶樻墸娲诲姩 -export const deleteRewardActivity = async (id: number) => { - return await request.delete({ url: '/promotion/reward-activity/delete?id=' + id }) -} diff --git a/src/api/mall/promotion/seckill/seckillActivity.ts b/src/api/mall/promotion/seckill/seckillActivity.ts deleted file mode 100644 index e834641..0000000 --- a/src/api/mall/promotion/seckill/seckillActivity.ts +++ /dev/null @@ -1,68 +0,0 @@ -import request from '@/config/axios' -import { Sku, Spu } from '@/api/mall/product/spu' - -export interface SeckillActivityVO { - id?: number - spuId?: number - name?: string - status?: number - remark?: string - startTime?: Date - endTime?: Date - sort?: number - configIds?: string - orderCount?: number - userCount?: number - totalPrice?: number - totalLimitCount?: number - singleLimitCount?: number - stock?: number - totalStock?: number - products?: SeckillProductVO[] -} - -// 绉掓潃娲诲姩鎵�闇�灞炴�� -export interface SeckillProductVO { - skuId: number - seckillPrice: number - stock: number -} - -// 鎵╁睍 Sku 閰嶇疆 -export type SkuExtension = Sku & { - productConfig: SeckillProductVO -} - -export interface SpuExtension extends Spu { - skus: SkuExtension[] // 閲嶅啓绫诲瀷 -} - -// 鏌ヨ绉掓潃娲诲姩鍒楄〃 -export const getSeckillActivityPage = async (params) => { - return await request.get({ url: '/promotion/seckill-activity/page', params }) -} - -// 鏌ヨ绉掓潃娲诲姩璇︽儏 -export const getSeckillActivity = async (id: number) => { - return await request.get({ url: '/promotion/seckill-activity/get?id=' + id }) -} - -// 鏂板绉掓潃娲诲姩 -export const createSeckillActivity = async (data: SeckillActivityVO) => { - return await request.post({ url: '/promotion/seckill-activity/create', data }) -} - -// 淇敼绉掓潃娲诲姩 -export const updateSeckillActivity = async (data: SeckillActivityVO) => { - return await request.put({ url: '/promotion/seckill-activity/update', data }) -} - -// 鍏抽棴绉掓潃娲诲姩 -export const closeSeckillActivity = async (id: number) => { - return await request.put({ url: '/promotion/seckill-activity/close?id=' + id }) -} - -// 鍒犻櫎绉掓潃娲诲姩 -export const deleteSeckillActivity = async (id: number) => { - return await request.delete({ url: '/promotion/seckill-activity/delete?id=' + id }) -} diff --git a/src/api/mall/promotion/seckill/seckillConfig.ts b/src/api/mall/promotion/seckill/seckillConfig.ts deleted file mode 100644 index 37d9b54..0000000 --- a/src/api/mall/promotion/seckill/seckillConfig.ts +++ /dev/null @@ -1,53 +0,0 @@ -import request from '@/config/axios' - -// 绉掓潃鏃舵 VO -export interface SeckillConfigVO { - id: number // 缂栧彿 - name: string // 绉掓潃鏃舵鍚嶇О - startTime: string // 寮�濮嬫椂闂寸偣 - endTime: string // 缁撴潫鏃堕棿鐐� - sliderPicUrls: string[] // 绉掓潃杞挱鍥� - status: number // 娲诲姩鐘舵�� -} - -// 绉掓潃鏃舵 API -export const SeckillConfigApi = { - // 鏌ヨ绉掓潃鏃舵鍒嗛〉 - getSeckillConfigPage: async (params: any) => { - return await request.get({ url: `/promotion/seckill-config/page`, params }) - }, - - // 鏌ヨ绉掓潃鏃舵鍒楄〃 - getSimpleSeckillConfigList: async () => { - return await request.get({ url: `/promotion/seckill-config/list` }) - }, - - // 鏌ヨ绉掓潃鏃舵璇︽儏 - getSeckillConfig: async (id: number) => { - return await request.get({ url: `/promotion/seckill-config/get?id=` + id }) - }, - - // 鏂板绉掓潃鏃舵 - createSeckillConfig: async (data: SeckillConfigVO) => { - return await request.post({ url: `/promotion/seckill-config/create`, data }) - }, - - // 淇敼绉掓潃鏃舵 - updateSeckillConfig: async (data: SeckillConfigVO) => { - return await request.put({ url: `/promotion/seckill-config/update`, data }) - }, - - // 鍒犻櫎绉掓潃鏃舵 - deleteSeckillConfig: async (id: number) => { - return await request.delete({ url: `/promotion/seckill-config/delete?id=` + id }) - }, - - // 淇敼鏃舵閰嶇疆鐘舵�� - updateSeckillConfigStatus: async (id: number, status: number) => { - const data = { - id, - status - } - return request.put({ url: '/promotion/seckill-config/update-status', data: data }) - } -} diff --git a/src/api/mall/statistics/common.ts b/src/api/mall/statistics/common.ts deleted file mode 100644 index 3d96439..0000000 --- a/src/api/mall/statistics/common.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** 鏁版嵁瀵圭収 Response VO */ -export interface DataComparisonRespVO<T> { - value: T - reference: T -} diff --git a/src/api/mall/statistics/member.ts b/src/api/mall/statistics/member.ts deleted file mode 100644 index d9accf9..0000000 --- a/src/api/mall/statistics/member.ts +++ /dev/null @@ -1,123 +0,0 @@ -import request from '@/config/axios' -import dayjs from 'dayjs' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' -import { formatDate } from '@/utils/formatTime' - -/** 浼氬憳鍒嗘瀽 Request VO */ -export interface MemberAnalyseReqVO { - times: dayjs.ConfigType[] -} - -/** 浼氬憳鍒嗘瀽 Response VO */ -export interface MemberAnalyseRespVO { - visitUserCount: number - orderUserCount: number - payUserCount: number - atv: number - comparison: DataComparisonRespVO<MemberAnalyseComparisonRespVO> -} - -/** 浼氬憳鍒嗘瀽瀵圭収鏁版嵁 Response VO */ -export interface MemberAnalyseComparisonRespVO { - registerUserCount: number - visitUserCount: number - rechargeUserCount: number -} - -/** 浼氬憳鍦板尯缁熻 Response VO */ -export interface MemberAreaStatisticsRespVO { - areaId: number - areaName: string - userCount: number - orderCreateUserCount: number - orderPayUserCount: number - orderPayPrice: number -} - -/** 浼氬憳鎬у埆缁熻 Response VO */ -export interface MemberSexStatisticsRespVO { - sex: number - userCount: number -} - -/** 浼氬憳缁熻 Response VO */ -export interface MemberSummaryRespVO { - userCount: number - rechargeUserCount: number - rechargePrice: number - expensePrice: number -} - -/** 浼氬憳缁堢缁熻 Response VO */ -export interface MemberTerminalStatisticsRespVO { - terminal: number - userCount: number -} - -/** 浼氬憳鏁伴噺缁熻 Response VO */ -export interface MemberCountRespVO { - /** 鐢ㄦ埛璁块棶閲� */ - visitUserCount: string - /** 娉ㄥ唽鐢ㄦ埛鏁伴噺 */ - registerUserCount: number -} - -/** 浼氬憳娉ㄥ唽鏁伴噺 Response VO */ -export interface MemberRegisterCountRespVO { - date: string - count: number -} - -// 鏌ヨ浼氬憳缁熻 -export const getMemberSummary = () => { - return request.get<MemberSummaryRespVO>({ - url: '/statistics/member/summary' - }) -} - -// 鏌ヨ浼氬憳鍒嗘瀽鏁版嵁 -export const getMemberAnalyse = (params: MemberAnalyseReqVO) => { - return request.get<MemberAnalyseRespVO>({ - url: '/statistics/member/analyse', - params: { times: [formatDate(params.times[0]), formatDate(params.times[1])] } - }) -} - -// 鎸夌収鐪佷唤锛屾煡璇細鍛樼粺璁″垪琛� -export const getMemberAreaStatisticsList = () => { - return request.get<MemberAreaStatisticsRespVO[]>({ - url: '/statistics/member/area-statistics-list' - }) -} - -// 鎸夌収鎬у埆锛屾煡璇細鍛樼粺璁″垪琛� -export const getMemberSexStatisticsList = () => { - return request.get<MemberSexStatisticsRespVO[]>({ - url: '/statistics/member/sex-statistics-list' - }) -} - -// 鎸夌収缁堢锛屾煡璇細鍛樼粺璁″垪琛� -export const getMemberTerminalStatisticsList = () => { - return request.get<MemberTerminalStatisticsRespVO[]>({ - url: '/statistics/member/terminal-statistics-list' - }) -} - -// 鑾峰緱鐢ㄦ埛鏁伴噺閲忓鐓� -export const getUserCountComparison = () => { - return request.get<DataComparisonRespVO<MemberCountRespVO>>({ - url: '/statistics/member/user-count-comparison' - }) -} - -// 鑾峰緱浼氬憳娉ㄥ唽鏁伴噺鍒楄〃 -export const getMemberRegisterCountList = ( - beginTime: dayjs.ConfigType, - endTime: dayjs.ConfigType -) => { - return request.get<MemberRegisterCountRespVO[]>({ - url: '/statistics/member/register-count-list', - params: { times: [formatDate(beginTime), formatDate(endTime)] } - }) -} diff --git a/src/api/mall/statistics/pay.ts b/src/api/mall/statistics/pay.ts deleted file mode 100644 index f5d14c9..0000000 --- a/src/api/mall/statistics/pay.ts +++ /dev/null @@ -1,12 +0,0 @@ -import request from '@/config/axios' - -/** 鏀粯缁熻 */ -export interface PaySummaryRespVO { - /** 鍏呭�奸噾棰濓紝鍗曚綅鍒� */ - rechargePrice: number -} - -/** 鑾峰彇閽卞寘鍏呭�奸噾棰� */ -export const getWalletRechargePrice = async () => { - return await request.get<PaySummaryRespVO>({ url: `/statistics/pay/summary` }) -} diff --git a/src/api/mall/statistics/product.ts b/src/api/mall/statistics/product.ts deleted file mode 100644 index 798a2fa..0000000 --- a/src/api/mall/statistics/product.ts +++ /dev/null @@ -1,52 +0,0 @@ -import request from '@/config/axios' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' - -export interface ProductStatisticsVO { - id: number - day: string - spuId: number - spuName: string - spuPicUrl: string - browseCount: number - browseUserCount: number - favoriteCount: number - cartCount: number - orderCount: number - orderPayCount: number - orderPayPrice: number - afterSaleCount: number - afterSaleRefundPrice: number - browseConvertPercent: number -} - -// 鍟嗗搧缁熻 API -export const ProductStatisticsApi = { - // 鑾峰緱鍟嗗搧缁熻鍒嗘瀽 - getProductStatisticsAnalyse: (params: any) => { - return request.get<DataComparisonRespVO<ProductStatisticsVO>>({ - url: '/statistics/product/analyse', - params - }) - }, - // 鑾峰緱鍟嗗搧鐘跺喌鏄庣粏 - getProductStatisticsList: (params: any) => { - return request.get<ProductStatisticsVO[]>({ - url: '/statistics/product/list', - params - }) - }, - // 瀵煎嚭鑾峰緱鍟嗗搧鐘跺喌鏄庣粏 Excel - exportProductStatisticsExcel: (params: any) => { - return request.download({ - url: '/statistics/product/export-excel', - params - }) - }, - // 鑾峰緱鍟嗗搧鎺掕姒滃垎椤� - getProductStatisticsRankPage: async (params: any) => { - return await request.get({ - url: `/statistics/product/rank-page`, - params - }) - } -} diff --git a/src/api/mall/statistics/trade.ts b/src/api/mall/statistics/trade.ts deleted file mode 100644 index e59952a..0000000 --- a/src/api/mall/statistics/trade.ts +++ /dev/null @@ -1,119 +0,0 @@ -import request from '@/config/axios' -import dayjs from 'dayjs' -import { formatDate } from '@/utils/formatTime' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' - -/** 浜ゆ槗缁熻 Response VO */ -export interface TradeSummaryRespVO { - yesterdayOrderCount: number - monthOrderCount: number - yesterdayPayPrice: number - monthPayPrice: number -} - -/** 浜ゆ槗鐘跺喌 Request VO */ -export interface TradeTrendReqVO { - times: [dayjs.ConfigType, dayjs.ConfigType] -} - -/** 浜ゆ槗鐘跺喌缁熻 Response VO */ -export interface TradeTrendSummaryRespVO { - time: string - turnoverPrice: number - orderPayPrice: number - rechargePrice: number - expensePrice: number - walletPayPrice: number - brokerageSettlementPrice: number - afterSaleRefundPrice: number -} - -/** 浜ゆ槗璁㈠崟鏁伴噺 Response VO */ -export interface TradeOrderCountRespVO { - /** 寰呭彂璐� */ - undelivered?: number - /** 寰呮牳閿� */ - pickUp?: number - /** 閫�娆句腑 */ - afterSaleApply?: number - /** 鎻愮幇寰呭鏍� */ - auditingWithdraw?: number -} - -/** 浜ゆ槗璁㈠崟缁熻 Response VO */ -export interface TradeOrderSummaryRespVO { - /** 鏀粯璁㈠崟鍟嗗搧鏁� */ - orderPayCount?: number - /** 鎬绘敮浠橀噾棰濓紝鍗曚綅锛氬垎 */ - orderPayPrice?: number -} - -/** 璁㈠崟閲忚秼鍔跨粺璁� Response VO */ -export interface TradeOrderTrendRespVO { - /** 鏃ユ湡 */ - date: string - /** 璁㈠崟鏁伴噺 */ - orderPayCount: number - /** 璁㈠崟鏀粯閲戦 */ - orderPayPrice: number -} - -// 鏌ヨ浜ゆ槗缁熻 -export const getTradeStatisticsSummary = () => { - return request.get<DataComparisonRespVO<TradeSummaryRespVO>>({ - url: '/statistics/trade/summary' - }) -} - -// 鑾峰緱浜ゆ槗鐘跺喌缁熻 -export const getTradeStatisticsAnalyse = (params: TradeTrendReqVO) => { - return request.get<DataComparisonRespVO<TradeTrendSummaryRespVO>>({ - url: '/statistics/trade/analyse', - params: formatDateParam(params) - }) -} - -// 鑾峰緱浜ゆ槗鐘跺喌鏄庣粏 -export const getTradeStatisticsList = (params: TradeTrendReqVO) => { - return request.get<TradeTrendSummaryRespVO[]>({ - url: '/statistics/trade/list', - params: formatDateParam(params) - }) -} - -// 瀵煎嚭浜ゆ槗鐘跺喌鏄庣粏 -export const exportTradeStatisticsExcel = (params: TradeTrendReqVO) => { - return request.download({ - url: '/statistics/trade/export-excel', - params: formatDateParam(params) - }) -} - -// 鑾峰緱浜ゆ槗璁㈠崟鏁伴噺 -export const getOrderCount = async () => { - return await request.get<TradeOrderCountRespVO>({ url: `/statistics/trade/order-count` }) -} - -// 鑾峰緱浜ゆ槗璁㈠崟鏁伴噺瀵圭収 -export const getOrderComparison = async () => { - return await request.get<DataComparisonRespVO<TradeOrderSummaryRespVO>>({ - url: `/statistics/trade/order-comparison` - }) -} - -// 鑾峰緱璁㈠崟閲忚秼鍔跨粺璁� -export const getOrderCountTrendComparison = ( - type: number, - beginTime: dayjs.ConfigType, - endTime: dayjs.ConfigType -) => { - return request.get<DataComparisonRespVO<TradeOrderTrendRespVO>[]>({ - url: '/statistics/trade/order-count-trend', - params: { type, beginTime: formatDate(beginTime), endTime: formatDate(endTime) } - }) -} - -/** 鏃堕棿鍙傛暟闇�瑕佹牸寮忓寲, 纭繚鎺ュ彛鑳借瘑鍒� */ -const formatDateParam = (params: TradeTrendReqVO) => { - return { times: [formatDate(params.times[0]), formatDate(params.times[1])] } as TradeTrendReqVO -} diff --git a/src/api/mall/trade/afterSale/index.ts b/src/api/mall/trade/afterSale/index.ts deleted file mode 100644 index a109ee6..0000000 --- a/src/api/mall/trade/afterSale/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -import request from '@/config/axios' - -export interface TradeAfterSaleVO { - id?: number | null // 鍞悗缂栧彿锛屼富閿嚜澧� - no?: string // 鍞悗鍗曞彿 - status?: number | null // 閫�娆剧姸鎬� - way?: number | null // 鍞悗鏂瑰紡 - type?: number | null // 鍞悗绫诲瀷 - userId?: number | null // 鐢ㄦ埛缂栧彿 - applyReason?: string // 鐢宠鍘熷洜 - applyDescription?: string // 琛ュ厖鎻忚堪 - applyPicUrls?: string[] // 琛ュ厖鍑瘉鍥剧墖 - orderId?: number | null // 浜ゆ槗璁㈠崟缂栧彿 - orderNo?: string // 璁㈠崟娴佹按鍙� - orderItemId?: number | null // 浜ゆ槗璁㈠崟椤圭紪鍙� - spuId?: number | null // 鍟嗗搧 SPU 缂栧彿 - spuName?: string // 鍟嗗搧 SPU 鍚嶇О - skuId?: number | null // 鍟嗗搧 SKU 缂栧彿 - properties?: ProductPropertiesVO[] // 灞炴�ф暟缁� - picUrl?: string // 鍟嗗搧鍥剧墖 - count?: number | null // 閫�璐у晢鍝佹暟閲� - auditTime?: Date // 瀹℃壒鏃堕棿 - auditUserId?: number | null // 瀹℃壒浜� - auditReason?: string // 瀹℃壒澶囨敞 - refundPrice?: number | null // 閫�娆鹃噾棰濓紝鍗曚綅锛氬垎銆� - payRefundId?: number | null // 鏀粯閫�娆剧紪鍙� - refundTime?: Date // 閫�娆炬椂闂� - logisticsId?: number | null // 閫�璐х墿娴佸叕鍙哥紪鍙� - logisticsNo?: string // 閫�璐х墿娴佸崟鍙� - deliveryTime?: Date // 閫�璐ф椂闂� - receiveTime?: Date // 鏀惰揣鏃堕棿 - receiveReason?: string // 鏀惰揣澶囨敞 -} - -export interface ProductPropertiesVO { - propertyId?: number | null // 灞炴�х殑缂栧彿 - propertyName?: string // 灞炴�х殑鍚嶇О - valueId?: number | null //灞炴�у�肩殑缂栧彿 - valueName?: string // 灞炴�у�肩殑鍚嶇О -} - -// 鑾峰緱浜ゆ槗鍞悗鍒嗛〉 -export const getAfterSalePage = async (params) => { - return await request.get({ url: `/trade/after-sale/page`, params }) -} - -// 鑾峰緱浜ゆ槗鍞悗璇︽儏 -export const getAfterSale = async (id: any) => { - return await request.get({ url: `/trade/after-sale/get-detail?id=${id}` }) -} - -// 鍚屾剰鍞悗 -export const agree = async (id: any) => { - return await request.put({ url: `/trade/after-sale/agree?id=${id}` }) -} - -// 鎷掔粷鍞悗 -export const disagree = async (data: any) => { - return await request.put({ url: `/trade/after-sale/disagree`, data }) -} - -// 纭鏀惰揣 -export const receive = async (id: any) => { - return await request.put({ url: `/trade/after-sale/receive?id=${id}` }) -} - -// 鎷掔粷鏀惰揣 -export const refuse = async (id: any) => { - return await request.put({ url: `/trade/after-sale/refuse?id=${id}` }) -} - -// 纭閫�娆� -export const refund = async (id: any) => { - return await request.put({ url: `/trade/after-sale/refund?id=${id}` }) -} diff --git a/src/api/mall/trade/brokerage/record/index.ts b/src/api/mall/trade/brokerage/record/index.ts deleted file mode 100644 index 7df9a22..0000000 --- a/src/api/mall/trade/brokerage/record/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import request from '@/config/axios' - -// 鏌ヨ浣i噾璁板綍鍒楄〃 -export const getBrokerageRecordPage = async (params: any) => { - return await request.get({ url: `/trade/brokerage-record/page`, params }) -} - -// 鏌ヨ浣i噾璁板綍璇︽儏 -export const getBrokerageRecord = async (id: number) => { - return await request.get({ url: `/trade/brokerage-record/get?id=` + id }) -} diff --git a/src/api/mall/trade/brokerage/user/index.ts b/src/api/mall/trade/brokerage/user/index.ts deleted file mode 100644 index 1fed3bf..0000000 --- a/src/api/mall/trade/brokerage/user/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import request from '@/config/axios' - -export interface BrokerageUserVO { - id: number - bindUserId: number - bindUserTime: Date - brokerageEnabled: boolean - brokerageTime: Date - price: number - frozenPrice: number - - nickname: string - avatar: string -} - -// 鏌ヨ鍒嗛攢鐢ㄦ埛鍒楄〃 -export const getBrokerageUserPage = async (params: any) => { - return await request.get({ url: `/trade/brokerage-user/page`, params }) -} - -// 鏌ヨ鍒嗛攢鐢ㄦ埛璇︽儏 -export const getBrokerageUser = async (id: number) => { - return await request.get({ url: `/trade/brokerage-user/get?id=` + id }) -} - -// 淇敼鎺ㄥ箍鍛� -export const updateBindUser = async (data: any) => { - return await request.put({ url: `/trade/brokerage-user/update-bind-user`, data }) -} - -// 娓呴櫎鎺ㄥ箍鍛� -export const clearBindUser = async (data: any) => { - return await request.put({ url: `/trade/brokerage-user/clear-bind-user`, data }) -} - -// 淇敼鎺ㄥ箍璧勬牸 -export const updateBrokerageEnabled = async (data: any) => { - return await request.put({ url: `/trade/brokerage-user/update-brokerage-enable`, data }) -} diff --git a/src/api/mall/trade/brokerage/withdraw/index.ts b/src/api/mall/trade/brokerage/withdraw/index.ts deleted file mode 100644 index c93286a..0000000 --- a/src/api/mall/trade/brokerage/withdraw/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import request from '@/config/axios' - -export interface BrokerageWithdrawVO { - id: number - userId: number - price: number - feePrice: number - totalPrice: number - type: number - name: string - accountNo: string - bankName: string - bankAddress: string - accountQrCodeUrl: string - status: number - auditReason: string - auditTime: Date - remark: string -} - -// 鏌ヨ浣i噾鎻愮幇鍒楄〃 -export const getBrokerageWithdrawPage = async (params: any) => { - return await request.get({ url: `/trade/brokerage-withdraw/page`, params }) -} - -// 鏌ヨ浣i噾鎻愮幇璇︽儏 -export const getBrokerageWithdraw = async (id: number) => { - return await request.get({ url: `/trade/brokerage-withdraw/get?id=` + id }) -} - -// 浣i噾鎻愮幇 - 閫氳繃鐢宠 -export const approveBrokerageWithdraw = async (id: number) => { - return await request.put({ url: `/trade/brokerage-withdraw/approve?id=` + id }) -} - -// 瀹℃牳浣i噾鎻愮幇 - 椹冲洖鐢宠 -export const rejectBrokerageWithdraw = async (data: BrokerageWithdrawVO) => { - return await request.put({ url: `/trade/brokerage-withdraw/reject`, data }) -} diff --git a/src/api/mall/trade/config/index.ts b/src/api/mall/trade/config/index.ts deleted file mode 100644 index 43fdbdf..0000000 --- a/src/api/mall/trade/config/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import request from '@/config/axios' - -export interface ConfigVO { - brokerageEnabled: boolean - brokerageEnabledCondition: number - brokerageBindMode: number - brokeragePosterUrls: string - brokerageFirstPercent: number - brokerageSecondPercent: number - brokerageWithdrawMinPrice: number - brokerageFrozenDays: number - brokerageWithdrawTypes: string -} - -// 鏌ヨ浜ゆ槗涓績閰嶇疆璇︽儏 -export const getTradeConfig = async () => { - return await request.get({ url: `/trade/config/get` }) -} - -// 淇濆瓨浜ゆ槗涓績閰嶇疆 -export const saveTradeConfig = async (data: ConfigVO) => { - return await request.put({ url: `/trade/config/save`, data }) -} diff --git a/src/api/mall/trade/delivery/express/index.ts b/src/api/mall/trade/delivery/express/index.ts deleted file mode 100644 index 0070bcd..0000000 --- a/src/api/mall/trade/delivery/express/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import request from '@/config/axios' - -export interface DeliveryExpressVO { - id: number - code: string - name: string - logo: string - sort: number - status: number -} - -// 鏌ヨ蹇�掑叕鍙稿垪琛� -export const getDeliveryExpressPage = async (params: PageParam) => { - return await request.get({ url: '/trade/delivery/express/page', params }) -} - -// 鏌ヨ蹇�掑叕鍙歌鎯� -export const getDeliveryExpress = async (id: number) => { - return await request.get({ url: '/trade/delivery/express/get?id=' + id }) -} - -// 鑾峰緱蹇�掑叕鍙哥簿绠�淇℃伅鍒楄〃 -export const getSimpleDeliveryExpressList = () => { - return request.get({ url: '/trade/delivery/express/list-all-simple' }) -} - -// 鏂板蹇�掑叕鍙� -export const createDeliveryExpress = async (data: DeliveryExpressVO) => { - return await request.post({ url: '/trade/delivery/express/create', data }) -} - -// 淇敼蹇�掑叕鍙� -export const updateDeliveryExpress = async (data: DeliveryExpressVO) => { - return await request.put({ url: '/trade/delivery/express/update', data }) -} - -// 鍒犻櫎蹇�掑叕鍙� -export const deleteDeliveryExpress = async (id: number) => { - return await request.delete({ url: '/trade/delivery/express/delete?id=' + id }) -} - -// 瀵煎嚭蹇�掑叕鍙� Excel -export const exportDeliveryExpressApi = async (params) => { - return await request.download({ url: '/trade/delivery/express/export-excel', params }) -} diff --git a/src/api/mall/trade/delivery/expressTemplate/index.ts b/src/api/mall/trade/delivery/expressTemplate/index.ts deleted file mode 100644 index 9ed23bc..0000000 --- a/src/api/mall/trade/delivery/expressTemplate/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import request from '@/config/axios' - -export interface DeliveryExpressTemplateVO { - id: number - name: string - chargeMode: number - sort: number - templateCharge: ExpressTemplateChargeVO[] - templateFree: ExpressTemplateFreeVO[] -} - -export declare type ExpressTemplateChargeVO = { - areaIds: number[] - startCount: number - startPrice: number - extraCount: number - extraPrice: number -} - -export declare type ExpressTemplateFreeVO = { - areaIds: number[] - freeCount: number - freePrice: number -} - -// 鏌ヨ蹇�掕繍璐规ā鏉垮垪琛� -export const getDeliveryExpressTemplatePage = async (params: PageParam) => { - return await request.get({ url: '/trade/delivery/express-template/page', params }) -} - -// 鏌ヨ蹇�掕繍璐规ā鏉胯鎯� -export const getDeliveryExpressTemplate = async (id: number) => { - return await request.get({ url: '/trade/delivery/express-template/get?id=' + id }) -} - -// 鏌ヨ蹇�掕繍璐规ā鏉胯鎯� -export const getSimpleTemplateList = async () => { - return await request.get({ url: '/trade/delivery/express-template/list-all-simple' }) -} - -// 鏂板蹇�掕繍璐规ā鏉� -export const createDeliveryExpressTemplate = async (data: DeliveryExpressTemplateVO) => { - return await request.post({ url: '/trade/delivery/express-template/create', data }) -} - -// 淇敼蹇�掕繍璐规ā鏉� -export const updateDeliveryExpressTemplate = async (data: DeliveryExpressTemplateVO) => { - return await request.put({ url: '/trade/delivery/express-template/update', data }) -} - -// 鍒犻櫎蹇�掕繍璐规ā鏉� -export const deleteDeliveryExpressTemplate = async (id: number) => { - return await request.delete({ url: '/trade/delivery/express-template/delete?id=' + id }) -} diff --git a/src/api/mall/trade/delivery/pickUpStore/index.ts b/src/api/mall/trade/delivery/pickUpStore/index.ts deleted file mode 100644 index c317502..0000000 --- a/src/api/mall/trade/delivery/pickUpStore/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import request from '@/config/axios' - -export interface DeliveryPickUpStoreVO { - id: number - name: string - introduction: string - phone: string - areaId: number - detailAddress: string - logo: string - openingTime: string - closingTime: string - latitude: number - longitude: number - status: number -} - -// 鏌ヨ鑷彁闂ㄥ簵鍒楄〃 -export const getDeliveryPickUpStorePage = async (params) => { - return await request.get({ url: '/trade/delivery/pick-up-store/page', params }) -} - -// 鏌ヨ鑷彁闂ㄥ簵璇︽儏 -export const getDeliveryPickUpStore = async (id: number) => { - return await request.get({ url: '/trade/delivery/pick-up-store/get?id=' + id }) -} - -// 鏌ヨ鑷彁闂ㄥ簵绮剧畝鍒楄〃 -export const getListAllSimple = async (): Promise<DeliveryPickUpStoreVO[]> => { - return await request.get({ url: '/trade/delivery/pick-up-store/list-all-simple' }) -} - -// 鏂板鑷彁闂ㄥ簵 -export const createDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => { - return await request.post({ url: '/trade/delivery/pick-up-store/create', data }) -} - -// 淇敼鑷彁闂ㄥ簵 -export const updateDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => { - return await request.put({ url: '/trade/delivery/pick-up-store/update', data }) -} - -// 鍒犻櫎鑷彁闂ㄥ簵 -export const deleteDeliveryPickUpStore = async (id: number) => { - return await request.delete({ url: '/trade/delivery/pick-up-store/delete?id=' + id }) -} diff --git a/src/api/mall/trade/order/index.ts b/src/api/mall/trade/order/index.ts deleted file mode 100644 index 37fee8c..0000000 --- a/src/api/mall/trade/order/index.ts +++ /dev/null @@ -1,188 +0,0 @@ -import request from '@/config/axios' - -export interface OrderVO { - // ========== 璁㈠崟鍩烘湰淇℃伅 ========== - id?: number | null // 璁㈠崟缂栧彿 - no?: string // 璁㈠崟娴佹按鍙� - createTime?: Date | null // 涓嬪崟鏃堕棿 - type?: number | null // 璁㈠崟绫诲瀷 - terminal?: number | null // 璁㈠崟鏉ユ簮 - userId?: number | null // 鐢ㄦ埛缂栧彿 - userIp?: string // 鐢ㄦ埛 IP - userRemark?: string // 鐢ㄦ埛澶囨敞 - status?: number | null // 璁㈠崟鐘舵�� - productCount?: number | null // 璐拱鐨勫晢鍝佹暟閲� - finishTime?: Date | null // 璁㈠崟瀹屾垚鏃堕棿 - cancelTime?: Date | null // 璁㈠崟鍙栨秷鏃堕棿 - cancelType?: number | null // 鍙栨秷绫诲瀷 - remark?: string // 鍟嗗澶囨敞 - - // ========== 浠锋牸 + 鏀粯鍩烘湰淇℃伅 ========== - payOrderId?: number | null // 鏀粯璁㈠崟缂栧彿 - payStatus?: boolean // 鏄惁宸叉敮浠� - payTime?: Date | null // 浠樻鏃堕棿 - payChannelCode?: string // 鏀粯娓犻亾 - totalPrice?: number | null // 鍟嗗搧鍘熶环锛堟�伙級 - discountPrice?: number | null // 璁㈠崟浼樻儬锛堟�伙級 - deliveryPrice?: number | null // 杩愯垂閲戦 - adjustPrice?: number | null // 璁㈠崟璋冧环锛堟�伙級 - payPrice?: number | null // 搴斾粯閲戦锛堟�伙級 - // ========== 鏀朵欢 + 鐗╂祦鍩烘湰淇℃伅 ========== - deliveryType?: number | null // 鍙戣揣鏂瑰紡 - pickUpStoreId?: number // 鑷彁闂ㄥ簵缂栧彿 - pickUpVerifyCode?: string // 鑷彁鏍搁攢鐮� - deliveryTemplateId?: number | null // 閰嶉�佹ā鏉跨紪鍙� - logisticsId?: number | null // 鍙戣揣鐗╂祦鍏徃缂栧彿 - logisticsNo?: string // 鍙戣揣鐗╂祦鍗曞彿 - deliveryTime?: Date | null // 鍙戣揣鏃堕棿 - receiveTime?: Date | null // 鏀惰揣鏃堕棿 - receiverName?: string // 鏀朵欢浜哄悕绉� - receiverMobile?: string // 鏀朵欢浜烘墜鏈� - receiverPostCode?: number | null // 鏀朵欢浜洪偖缂� - receiverAreaId?: number | null // 鏀朵欢浜哄湴鍖虹紪鍙� - receiverAreaName?: string //鏀朵欢浜哄湴鍖哄悕瀛� - receiverDetailAddress?: string // 鏀朵欢浜鸿缁嗗湴鍧� - - // ========== 鍞悗鍩烘湰淇℃伅 ========== - afterSaleStatus?: number | null // 鍞悗鐘舵�� - refundPrice?: number | null // 閫�娆鹃噾棰� - - // ========== 钀ラ攢鍩烘湰淇℃伅 ========== - couponId?: number | null // 浼樻儬鍔电紪鍙� - couponPrice?: number | null // 浼樻儬鍔靛噺鍏嶉噾棰� - pointPrice?: number | null // 绉垎鎶垫墸鐨勯噾棰� - vipPrice?: number | null // VIP 鍑忓厤閲戦 - - items?: OrderItemRespVO[] // 璁㈠崟椤瑰垪琛� - // 涓嬪崟鐢ㄦ埛淇℃伅 - user?: { - id?: number | null - nickname?: string - avatar?: string - } - // 鎺ㄥ箍鐢ㄦ埛淇℃伅 - brokerageUser?: { - id?: number | null - nickname?: string - avatar?: string - } - // 璁㈠崟鎿嶄綔鏃ュ織 - logs?: OrderLogRespVO[] -} - -export interface OrderLogRespVO { - content?: string - createTime?: Date - userType?: number -} - -export interface OrderItemRespVO { - // ========== 璁㈠崟椤瑰熀鏈俊鎭� ========== - id?: number | null // 缂栧彿 - userId?: number | null // 鐢ㄦ埛缂栧彿 - orderId?: number | null // 璁㈠崟缂栧彿 - // ========== 鍟嗗搧鍩烘湰淇℃伅 ========== - spuId?: number | null // 鍟嗗搧 SPU 缂栧彿 - spuName?: string //鍟嗗搧 SPU 鍚嶇О - skuId?: number | null // 鍟嗗搧 SKU 缂栧彿 - picUrl?: string //鍟嗗搧鍥剧墖 - count?: number | null //璐拱鏁伴噺 - // ========== 浠锋牸 + 鏀粯鍩烘湰淇℃伅 ========== - originalPrice?: number | null //鍟嗗搧鍘熶环锛堟�伙級 - originalUnitPrice?: number | null //鍟嗗搧鍘熶环锛堝崟锛� - discountPrice?: number | null //鍟嗗搧浼樻儬锛堟�伙級 - payPrice?: number | null //鍟嗗搧瀹炰粯閲戦锛堟�伙級 - orderPartPrice?: number | null //瀛愯鍗曞垎鎽婇噾棰濓紙鎬伙級 - orderDividePrice?: number | null //鍒嗘憡鍚庡瓙璁㈠崟瀹炰粯閲戦锛堟�伙級 - // ========== 钀ラ攢鍩烘湰淇℃伅 ========== - // TODO 鑺嬭壙锛氬湪鎹夋懜涓�涓� - // ========== 鍞悗鍩烘湰淇℃伅 ========== - afterSaleStatus?: number | null // 鍞悗鐘舵�� - properties?: ProductPropertiesVO[] //灞炴�ф暟缁� -} - -export interface ProductPropertiesVO { - propertyId?: number | null // 灞炴�х殑缂栧彿 - propertyName?: string // 灞炴�х殑鍚嶇О - valueId?: number | null //灞炴�у�肩殑缂栧彿 - valueName?: string // 灞炴�у�肩殑鍚嶇О -} - -/** 浜ゆ槗璁㈠崟缁熻 */ -export interface TradeOrderSummaryRespVO { - /** 璁㈠崟鏁伴噺 */ - orderCount?: number - /** 璁㈠崟閲戦 */ - orderPayPrice?: string - /** 閫�娆惧崟鏁� */ - afterSaleCount?: number - /** 閫�娆鹃噾棰� */ - afterSalePrice?: string -} - -// 鏌ヨ浜ゆ槗璁㈠崟鍒楄〃 -export const getOrderPage = async (params: any) => { - return await request.get({ url: `/trade/order/page`, params }) -} - -// 鏌ヨ浜ゆ槗璁㈠崟缁熻 -export const getOrderSummary = async (params: any) => { - return await request.get<TradeOrderSummaryRespVO>({ url: `/trade/order/summary`, params }) -} - -// 鏌ヨ浜ゆ槗璁㈠崟璇︽儏 -export const getOrder = async (id: number | null) => { - return await request.get({ url: `/trade/order/get-detail?id=` + id }) -} - -// 鏌ヨ浜ゆ槗璁㈠崟鐗╂祦璇︽儏 -export const getExpressTrackList = async (id: number | null) => { - return await request.get({ url: `/trade/order/get-express-track-list?id=` + id }) -} - -export interface DeliveryVO { - id?: number // 璁㈠崟缂栧彿 - logisticsId: number | null // 鐗╂祦鍏徃缂栧彿 - logisticsNo: string // 鐗╂祦缂栧彿 -} - -// 璁㈠崟鍙戣揣 -export const deliveryOrder = async (data: DeliveryVO) => { - return await request.put({ url: `/trade/order/delivery`, data }) -} - -// 璁㈠崟澶囨敞 -export const updateOrderRemark = async (data: any) => { - return await request.put({ url: `/trade/order/update-remark`, data }) -} - -// 璁㈠崟璋冧环 -export const updateOrderPrice = async (data: any) => { - return await request.put({ url: `/trade/order/update-price`, data }) -} - -// 淇敼璁㈠崟鍦板潃 -export const updateOrderAddress = async (data: any) => { - return await request.put({ url: `/trade/order/update-address`, data }) -} - -// 璁㈠崟鏍搁攢 -export const pickUpOrder = async (id: number) => { - return await request.put({ url: `/trade/order/pick-up-by-id?id=${id}` }) -} - -// 璁㈠崟鏍搁攢 -export const pickUpOrderByVerifyCode = async (pickUpVerifyCode: string) => { - return await request.put({ - url: `/trade/order/pick-up-by-verify-code`, - params: { pickUpVerifyCode } - }) -} - -// 鏌ヨ鏍搁攢鐮佸搴旂殑璁㈠崟 -export const getOrderByPickUpVerifyCode = async (pickUpVerifyCode: string) => { - return await request.get<OrderVO>({ - url: `/trade/order/get-by-pick-up-verify-code`, - params: { pickUpVerifyCode } - }) -} diff --git a/src/api/member/address/index.ts b/src/api/member/address/index.ts deleted file mode 100644 index a914f97..0000000 --- a/src/api/member/address/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import request from '@/config/axios' - -export interface AddressVO { - id: number - name: string - mobile: string - areaId: number - detailAddress: string - defaultStatus: boolean -} - -// 鏌ヨ鐢ㄦ埛鏀朵欢鍦板潃鍒楄〃 -export const getAddressList = async (params) => { - return await request.get({ url: `/member/address/list`, params }) -} diff --git a/src/api/member/config/index.ts b/src/api/member/config/index.ts deleted file mode 100644 index 7ddca16..0000000 --- a/src/api/member/config/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import request from '@/config/axios' - -export interface ConfigVO { - id: number - pointTradeDeductEnable: number - pointTradeDeductUnitPrice: number - pointTradeDeductMaxPrice: number - pointTradeGivePoint: number -} - -// 鏌ヨ绉垎璁剧疆璇︽儏 -export const getConfig = async () => { - return await request.get({ url: `/member/config/get` }) -} - -// 鏂板淇敼绉垎璁剧疆 -export const saveConfig = async (data: ConfigVO) => { - return await request.put({ url: `/member/config/save`, data }) -} diff --git a/src/api/member/experience-record/index.ts b/src/api/member/experience-record/index.ts deleted file mode 100644 index 6d40a48..0000000 --- a/src/api/member/experience-record/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import request from '@/config/axios' - -export interface ExperienceRecordVO { - id: number - userId: number - bizId: string - bizType: number - title: string - description: string - experience: number - totalExperience: number -} - -// 鏌ヨ浼氬憳缁忛獙璁板綍鍒楄〃 -export const getExperienceRecordPage = async (params) => { - return await request.get({ url: `/member/experience-record/page`, params }) -} - -// 鏌ヨ浼氬憳缁忛獙璁板綍璇︽儏 -export const getExperienceRecord = async (id: number) => { - return await request.get({ url: `/member/experience-record/get?id=` + id }) -} diff --git a/src/api/member/group/index.ts b/src/api/member/group/index.ts deleted file mode 100644 index df3054e..0000000 --- a/src/api/member/group/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import request from '@/config/axios' - -export interface GroupVO { - id: number - name: string - remark: string - status: number -} - -// 鏌ヨ鐢ㄦ埛鍒嗙粍鍒楄〃 -export const getGroupPage = async (params: any) => { - return await request.get({ url: `/member/group/page`, params }) -} - -// 鏌ヨ鐢ㄦ埛鍒嗙粍璇︽儏 -export const getGroup = async (id: number) => { - return await request.get({ url: `/member/group/get?id=` + id }) -} - -// 鏂板鐢ㄦ埛鍒嗙粍 -export const createGroup = async (data: GroupVO) => { - return await request.post({ url: `/member/group/create`, data }) -} - -// 鏌ヨ鐢ㄦ埛鍒嗙粍 - 绮剧畝淇℃伅鍒楄〃 -export const getSimpleGroupList = async () => { - return await request.get({ url: `/member/group/list-all-simple` }) -} - -// 淇敼鐢ㄦ埛鍒嗙粍 -export const updateGroup = async (data: GroupVO) => { - return await request.put({ url: `/member/group/update`, data }) -} - -// 鍒犻櫎鐢ㄦ埛鍒嗙粍 -export const deleteGroup = async (id: number) => { - return await request.delete({ url: `/member/group/delete?id=` + id }) -} diff --git a/src/api/member/level/index.ts b/src/api/member/level/index.ts deleted file mode 100644 index 0ded493..0000000 --- a/src/api/member/level/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import request from '@/config/axios' - -export interface LevelVO { - id: number - name: string - experience: number - value: number - discountPercent: number - icon: string - bgUrl: string - status: number -} - -// 鏌ヨ浼氬憳绛夌骇鍒楄〃 -export const getLevelList = async (params) => { - return await request.get({ url: `/member/level/list`, params }) -} - -// 鏌ヨ浼氬憳绛夌骇璇︽儏 -export const getLevel = async (id: number) => { - return await request.get({ url: `/member/level/get?id=` + id }) -} - -// 鏌ヨ浼氬憳绛夌骇 - 绮剧畝淇℃伅鍒楄〃 -export const getSimpleLevelList = async () => { - return await request.get({ url: `/member/level/list-all-simple` }) -} - -// 鏂板浼氬憳绛夌骇 -export const createLevel = async (data: LevelVO) => { - return await request.post({ url: `/member/level/create`, data }) -} - -// 淇敼浼氬憳绛夌骇 -export const updateLevel = async (data: LevelVO) => { - return await request.put({ url: `/member/level/update`, data }) -} - -// 鍒犻櫎浼氬憳绛夌骇 -export const deleteLevel = async (id: number) => { - return await request.delete({ url: `/member/level/delete?id=` + id }) -} diff --git a/src/api/member/point/record/index.ts b/src/api/member/point/record/index.ts deleted file mode 100644 index f47ae46..0000000 --- a/src/api/member/point/record/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import request from '@/config/axios' - -export interface RecordVO { - id: number - bizId: string - bizType: string - title: string - description: string - point: number - totalPoint: number - userId: number - createDate: Date -} - -// 鏌ヨ鐢ㄦ埛绉垎璁板綍鍒楄〃 -export const getRecordPage = async (params) => { - return await request.get({ url: `/member/point/record/page`, params }) -} diff --git a/src/api/member/signin/config/index.ts b/src/api/member/signin/config/index.ts deleted file mode 100644 index 50a7d63..0000000 --- a/src/api/member/signin/config/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import request from '@/config/axios' - -export interface SignInConfigVO { - id?: number - day?: number - point?: number - experience?: number - status?: number -} - -// 鏌ヨ绉垎绛惧埌瑙勫垯鍒楄〃 -export const getSignInConfigList = async () => { - return await request.get({ url: `/member/sign-in/config/list` }) -} - -// 鏌ヨ绉垎绛惧埌瑙勫垯璇︽儏 -export const getSignInConfig = async (id: number) => { - return await request.get({ url: `/member/sign-in/config/get?id=` + id }) -} - -// 鏂板绉垎绛惧埌瑙勫垯 -export const createSignInConfig = async (data: SignInConfigVO) => { - return await request.post({ url: `/member/sign-in/config/create`, data }) -} - -// 淇敼绉垎绛惧埌瑙勫垯 -export const updateSignInConfig = async (data: SignInConfigVO) => { - return await request.put({ url: `/member/sign-in/config/update`, data }) -} - -// 鍒犻櫎绉垎绛惧埌瑙勫垯 -export const deleteSignInConfig = async (id: number) => { - return await request.delete({ url: `/member/sign-in/config/delete?id=` + id }) -} diff --git a/src/api/member/signin/record/index.ts b/src/api/member/signin/record/index.ts deleted file mode 100644 index 7d13702..0000000 --- a/src/api/member/signin/record/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import request from '@/config/axios' - -export interface SignInRecordVO { - id: number - userId: number - day: number - point: number -} - -// 鏌ヨ鐢ㄦ埛绛惧埌绉垎鍒楄〃 -export const getSignInRecordPage = async (params) => { - return await request.get({ url: `/member/sign-in/record/page`, params }) -} diff --git a/src/api/member/tag/index.ts b/src/api/member/tag/index.ts deleted file mode 100644 index 7ff6e9b..0000000 --- a/src/api/member/tag/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import request from '@/config/axios' - -export interface TagVO { - id: number - name: string -} - -// 鏌ヨ浼氬憳鏍囩鍒楄〃 -export const getMemberTagPage = async (params: any) => { - return await request.get({ url: `/member/tag/page`, params }) -} - -// 鏌ヨ浼氬憳鏍囩璇︽儏 -export const getMemberTag = async (id: number) => { - return await request.get({ url: `/member/tag/get?id=` + id }) -} - -// 鏌ヨ浼氬憳鏍囩 - 绮剧畝淇℃伅鍒楄〃 -export const getSimpleTagList = async () => { - return await request.get({ url: `/member/tag/list-all-simple` }) -} - -// 鏂板浼氬憳鏍囩 -export const createMemberTag = async (data: TagVO) => { - return await request.post({ url: `/member/tag/create`, data }) -} - -// 淇敼浼氬憳鏍囩 -export const updateMemberTag = async (data: TagVO) => { - return await request.put({ url: `/member/tag/update`, data }) -} - -// 鍒犻櫎浼氬憳鏍囩 -export const deleteMemberTag = async (id: number) => { - return await request.delete({ url: `/member/tag/delete?id=` + id }) -} diff --git a/src/api/member/user/index.ts b/src/api/member/user/index.ts deleted file mode 100644 index e38206a..0000000 --- a/src/api/member/user/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import request from '@/config/axios' - -export interface UserVO { - id: number - avatar: string | undefined - birthday: number | undefined - createTime: number | undefined - loginDate: number | undefined - loginIp: string - mark: string - mobile: string - name: string | undefined - nickname: string | undefined - registerIp: string - sex: number - status: number - areaId: number | undefined - areaName: string | undefined - levelName: string | null - point: number | undefined | null - totalPoint: number | undefined | null - experience: number | null | undefined -} - -// 鏌ヨ浼氬憳鐢ㄦ埛鍒楄〃 -export const getUserPage = async (params) => { - return await request.get({ url: `/member/user/page`, params }) -} - -// 鏌ヨ浼氬憳鐢ㄦ埛璇︽儏 -export const getUser = async (id: number) => { - return await request.get({ url: `/member/user/get?id=` + id }) -} - -// 淇敼浼氬憳鐢ㄦ埛 -export const updateUser = async (data: UserVO) => { - return await request.put({ url: `/member/user/update`, data }) -} - -// 淇敼浼氬憳鐢ㄦ埛绛夌骇 -export const updateUserLevel = async (data: any) => { - return await request.put({ url: `/member/user/update-level`, data }) -} - -// 淇敼浼氬憳鐢ㄦ埛绉垎 -export const updateUserPoint = async (data: any) => { - return await request.put({ url: `/member/user/update-point`, data }) -} - -// 淇敼浼氬憳鐢ㄦ埛浣欓 -export const updateUserBalance = async (data: any) => { - return await request.put({ url: `/member/user/update-balance`, data }) -} diff --git a/src/api/pay/app/index.ts b/src/api/pay/app/index.ts deleted file mode 100644 index 4bb06b3..0000000 --- a/src/api/pay/app/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -import request from '@/config/axios' - -export interface AppVO { - id: number - name: string - status: number - remark: string - payNotifyUrl: string - refundNotifyUrl: string - merchantId: number - merchantName: string - createTime: Date -} - -export interface AppPageReqVO extends PageParam { - name?: string - status?: number - remark?: string - payNotifyUrl?: string - refundNotifyUrl?: string - merchantName?: string - createTime?: Date[] -} - -export interface AppUpdateStatusReqVO { - id: number - status: number -} - -// 鏌ヨ鍒楄〃鏀粯搴旂敤 -export const getAppPage = (params: AppPageReqVO) => { - return request.get({ url: '/pay/app/page', params }) -} - -// 鏌ヨ璇︽儏鏀粯搴旂敤 -export const getApp = (id: number) => { - return request.get({ url: '/pay/app/get?id=' + id }) -} - -// 鏂板鏀粯搴旂敤 -export const createApp = (data: AppVO) => { - return request.post({ url: '/pay/app/create', data }) -} - -// 淇敼鏀粯搴旂敤 -export const updateApp = (data: AppVO) => { - return request.put({ url: '/pay/app/update', data }) -} - -// 鏀粯搴旂敤淇℃伅鐘舵�佷慨鏀� -export const changeAppStatus = (data: AppUpdateStatusReqVO) => { - return request.put({ url: '/pay/app/update-status', data: data }) -} - -// 鍒犻櫎鏀粯搴旂敤 -export const deleteApp = (id: number) => { - return request.delete({ url: '/pay/app/delete?id=' + id }) -} - -// 鑾峰緱鏀粯搴旂敤鍒楄〃 -export const getAppList = () => { - return request.get({ - url: '/pay/app/list' - }) -} diff --git a/src/api/pay/channel/index.ts b/src/api/pay/channel/index.ts deleted file mode 100644 index 0f4ff42..0000000 --- a/src/api/pay/channel/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import request from '@/config/axios' - -export interface ChannelVO { - id: number - code: string - config: string - status: number - remark: string - feeRate: number - appId: number - createTime: Date -} - -// 鏌ヨ鍒楄〃鏀粯娓犻亾 -export const getChannelPage = (params: PageParam) => { - return request.get({ url: '/pay/channel/page', params }) -} - -// 鏌ヨ璇︽儏鏀粯娓犻亾 -export const getChannel = (appId: string, code: string) => { - const params = { - appId: appId, - code: code - } - return request.get({ url: '/pay/channel/get', params: params }) -} - -// 鏂板鏀粯娓犻亾 -export const createChannel = (data: ChannelVO) => { - return request.post({ url: '/pay/channel/create', data }) -} - -// 淇敼鏀粯娓犻亾 -export const updateChannel = (data: ChannelVO) => { - return request.put({ url: '/pay/channel/update', data }) -} - -// 鍒犻櫎鏀粯娓犻亾 -export const deleteChannel = (id: number) => { - return request.delete({ url: '/pay/channel/delete?id=' + id }) -} - -// 瀵煎嚭鏀粯娓犻亾 -export const exportChannel = (params) => { - return request.download({ url: '/pay/channel/export-excel', params }) -} diff --git a/src/api/pay/demo/index.ts b/src/api/pay/demo/index.ts deleted file mode 100644 index 3824a8b..0000000 --- a/src/api/pay/demo/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import request from '@/config/axios' - -export interface DemoOrderVO { - spuId: number - createTime: Date -} - -// 鍒涘缓绀轰緥璁㈠崟 -export function createDemoOrder(data: DemoOrderVO) { - return request.post({ - url: '/pay/demo-order/create', - data: data - }) -} - -// 鑾峰緱绀轰緥璁㈠崟 -export function getDemoOrder(id: number) { - return request.get({ - url: '/pay/demo-order/get?id=' + id - }) -} - -// 鑾峰緱绀轰緥璁㈠崟鍒嗛〉 -export function getDemoOrderPage(query: PageParam) { - return request.get({ - url: '/pay/demo-order/page', - params: query - }) -} - -// 閫�娆剧ず渚嬭鍗� -export function refundDemoOrder(id) { - return request.put({ - url: '/pay/demo-order/refund?id=' + id - }) -} diff --git a/src/api/pay/demo/transfer/index.ts b/src/api/pay/demo/transfer/index.ts deleted file mode 100644 index a95b0d5..0000000 --- a/src/api/pay/demo/transfer/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import request from '@/config/axios' - -export interface DemoTransferVO { - price: number - type: number - userName: string - alipayLogonId: string - openid: string -} - -// 鍒涘缓绀轰緥杞处鍗� -export function createDemoTransfer(data: DemoTransferVO) { - return request.post({ - url: '/pay/demo-transfer/create', - data: data - }) -} - -// 鑾峰緱绀轰緥璁㈠崟鍒嗛〉 -export function getDemoTransferPage(query: PageParam) { - return request.get({ - url: '/pay/demo-transfer/page', - params: query - }) -} diff --git a/src/api/pay/notify/index.ts b/src/api/pay/notify/index.ts deleted file mode 100644 index dc8bd88..0000000 --- a/src/api/pay/notify/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import request from '@/config/axios' - -// 鑾峰緱鏀粯閫氱煡鏄庣粏 -export const getNotifyTaskDetail = (id) => { - return request.get({ - url: '/pay/notify/get-detail?id=' + id - }) -} - -// 鑾峰緱鏀粯閫氱煡鍒嗛〉 -export const getNotifyTaskPage = (query) => { - return request.get({ - url: '/pay/notify/page', - params: query - }) -} diff --git a/src/api/pay/order/index.ts b/src/api/pay/order/index.ts deleted file mode 100644 index 71960a8..0000000 --- a/src/api/pay/order/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -import request from '@/config/axios' - -export interface OrderVO { - id: number - merchantId: number - appId: number - channelId: number - channelCode: string - merchantOrderId: string - subject: string - body: string - notifyUrl: string - notifyStatus: number - amount: number - channelFeeRate: number - channelFeeAmount: number - status: number - userIp: string - expireTime: Date - successTime: Date - notifyTime: Date - successExtensionId: number - refundStatus: number - refundTimes: number - refundAmount: number - channelUserId: string - channelOrderNo: string - createTime: Date -} - -export interface OrderPageReqVO extends PageParam { - merchantId?: number - appId?: number - channelId?: number - channelCode?: string - merchantOrderId?: string - subject?: string - body?: string - notifyUrl?: string - notifyStatus?: number - amount?: number - channelFeeRate?: number - channelFeeAmount?: number - status?: number - expireTime?: Date[] - successTime?: Date[] - notifyTime?: Date[] - successExtensionId?: number - refundStatus?: number - refundTimes?: number - channelUserId?: string - channelOrderNo?: string - createTime?: Date[] -} - -export interface OrderExportReqVO { - merchantId?: number - appId?: number - channelId?: number - channelCode?: string - merchantOrderId?: string - subject?: string - body?: string - notifyUrl?: string - notifyStatus?: number - amount?: number - channelFeeRate?: number - channelFeeAmount?: number - status?: number - expireTime?: Date[] - successTime?: Date[] - notifyTime?: Date[] - successExtensionId?: number - refundStatus?: number - refundTimes?: number - channelUserId?: string - channelOrderNo?: string - createTime?: Date[] -} - -// 鏌ヨ鍒楄〃鏀粯璁㈠崟 -export const getOrderPage = async (params: OrderPageReqVO) => { - return await request.get({ url: '/pay/order/page', params }) -} - -// 鏌ヨ璇︽儏鏀粯璁㈠崟 -export const getOrder = async (id: number) => { - return await request.get({ url: '/pay/order/get?id=' + id }) -} - -// 鑾峰緱鏀粯璁㈠崟鐨勬槑缁� -export const getOrderDetail = async (id: number) => { - return await request.get({ url: '/pay/order/get-detail?id=' + id }) -} - -// 鎻愪氦鏀粯璁㈠崟 -export const submitOrder = async (data: any) => { - return await request.post({ url: '/pay/order/submit', data }) -} - -// 瀵煎嚭鏀粯璁㈠崟 -export const exportOrder = async (params: OrderExportReqVO) => { - return await request.download({ url: '/pay/order/export-excel', params }) -} diff --git a/src/api/pay/refund/index.ts b/src/api/pay/refund/index.ts deleted file mode 100644 index 4b587f2..0000000 --- a/src/api/pay/refund/index.ts +++ /dev/null @@ -1,116 +0,0 @@ -import request from '@/config/axios' - -export interface RefundVO { - id: number - merchantId: number - appId: number - channelId: number - channelCode: string - orderId: string - tradeNo: string - merchantOrderId: string - merchantRefundNo: string - notifyUrl: string - notifyStatus: number - status: number - type: number - payAmount: number - refundAmount: number - reason: string - userIp: string - channelOrderNo: string - channelRefundNo: string - channelErrorCode: string - channelErrorMsg: string - channelExtras: string - expireTime: Date - successTime: Date - notifyTime: Date - createTime: Date -} - -export interface RefundPageReqVO extends PageParam { - merchantId?: number - appId?: number - channelId?: number - channelCode?: string - orderId?: string - tradeNo?: string - merchantOrderId?: string - merchantRefundNo?: string - notifyUrl?: string - notifyStatus?: number - status?: number - type?: number - payAmount?: number - refundAmount?: number - reason?: string - userIp?: string - channelOrderNo?: string - channelRefundNo?: string - channelErrorCode?: string - channelErrorMsg?: string - channelExtras?: string - expireTime?: Date[] - successTime?: Date[] - notifyTime?: Date[] - createTime?: Date[] -} - -export interface PayRefundExportReqVO { - merchantId?: number - appId?: number - channelId?: number - channelCode?: string - orderId?: string - tradeNo?: string - merchantOrderId?: string - merchantRefundNo?: string - notifyUrl?: string - notifyStatus?: number - status?: number - type?: number - payAmount?: number - refundAmount?: number - reason?: string - userIp?: string - channelOrderNo?: string - channelRefundNo?: string - channelErrorCode?: string - channelErrorMsg?: string - channelExtras?: string - expireTime?: Date[] - successTime?: Date[] - notifyTime?: Date[] - createTime?: Date[] -} - -// 鏌ヨ鍒楄〃閫�娆捐鍗� -export const getRefundPage = (params: RefundPageReqVO) => { - return request.get({ url: '/pay/refund/page', params }) -} - -// 鏌ヨ璇︽儏閫�娆捐鍗� -export const getRefund = (id: number) => { - return request.get({ url: '/pay/refund/get?id=' + id }) -} - -// 鏂板閫�娆捐鍗� -export const createRefund = (data: RefundVO) => { - return request.post({ url: '/pay/refund/create', data }) -} - -// 淇敼閫�娆捐鍗� -export const updateRefund = (data: RefundVO) => { - return request.put({ url: '/pay/refund/update', data }) -} - -// 鍒犻櫎閫�娆捐鍗� -export const deleteRefund = (id: number) => { - return request.delete({ url: '/pay/refund/delete?id=' + id }) -} - -// 瀵煎嚭閫�娆捐鍗� -export const exportRefund = (params: PayRefundExportReqVO) => { - return request.download({ url: '/pay/refund/export-excel', params }) -} diff --git a/src/api/pay/transfer/index.ts b/src/api/pay/transfer/index.ts deleted file mode 100644 index 7a58abf..0000000 --- a/src/api/pay/transfer/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import request from '@/config/axios' - -export interface TransferVO { - appId: number - channelCode: string - merchantTransferId: string - type: number - price: number - subject: string - userName: string - alipayLogonId: string - openid: string -} - -// 鏂板杞处鍗� -export const createTransfer = async (data: TransferVO) => { - return await request.post({ url: `/pay/transfer/create`, data }) -} - -// 鏌ヨ杞处鍗曞垪琛� -export const getTransferPage = async (params) => { - return await request.get({ url: `/pay/transfer/page`, params }) -} - -export const getTransfer = async (id: number) => { - return await request.get({ url: '/pay/transfer/get?id=' + id }) -} diff --git a/src/api/pay/wallet/balance/index.ts b/src/api/pay/wallet/balance/index.ts deleted file mode 100644 index 3e5ab36..0000000 --- a/src/api/pay/wallet/balance/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import request from '@/config/axios' - -/** 鐢ㄦ埛閽卞寘鏌ヨ鍙傛暟 */ -export interface PayWalletUserReqVO { - userId: number -} -/** 閽卞寘 VO */ -export interface WalletVO { - id: number - userId: number - userType: number - balance: number - totalExpense: number - totalRecharge: number - freezePrice: number -} - -/** 鏌ヨ鐢ㄦ埛閽卞寘璇︽儏 */ -export const getWallet = async (params: PayWalletUserReqVO) => { - return await request.get<WalletVO>({ url: `/pay/wallet/get`, params }) -} - -// 鏌ヨ浼氬憳閽卞寘鍒楄〃 -export const getWalletPage = async (params) => { - return await request.get({ url: `/pay/wallet/page`, params }) -} diff --git a/src/api/pay/wallet/rechargePackage/index.ts b/src/api/pay/wallet/rechargePackage/index.ts deleted file mode 100644 index c8e4cc9..0000000 --- a/src/api/pay/wallet/rechargePackage/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import request from '@/config/axios' - -export interface WalletRechargePackageVO { - id: number - name: string - payPrice: number - bonusPrice: number - status: number -} - -// 鏌ヨ濂楅鍏呭�煎垪琛� -export const getWalletRechargePackagePage = async (params) => { - return await request.get({ url: '/pay/wallet-recharge-package/page', params }) -} - -// 鏌ヨ濂楅鍏呭�艰鎯� -export const getWalletRechargePackage = async (id: number) => { - return await request.get({ url: '/pay/wallet-recharge-package/get?id=' + id }) -} - -// 鏂板濂楅鍏呭�� -export const createWalletRechargePackage = async (data: WalletRechargePackageVO) => { - return await request.post({ url: '/pay/wallet-recharge-package/create', data }) -} - -// 淇敼濂楅鍏呭�� -export const updateWalletRechargePackage = async (data: WalletRechargePackageVO) => { - return await request.put({ url: '/pay/wallet-recharge-package/update', data }) -} - -// 鍒犻櫎濂楅鍏呭�� -export const deleteWalletRechargePackage = async (id: number) => { - return await request.delete({ url: '/pay/wallet-recharge-package/delete?id=' + id }) -} diff --git a/src/api/pay/wallet/transaction/index.ts b/src/api/pay/wallet/transaction/index.ts deleted file mode 100644 index 3377ffa..0000000 --- a/src/api/pay/wallet/transaction/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import request from '@/config/axios' - -export interface WalletTransactionVO { - id: number - walletId: number - title: string - price: number - balance: number -} - -// 鏌ヨ浼氬憳閽卞寘娴佹按鍒楄〃 -export const getWalletTransactionPage = async (params) => { - return await request.get({ url: `/pay/wallet-transaction/page`, params }) -} diff --git a/src/views/ai/chat/index/components/conversation/ConversationList.vue b/src/views/ai/chat/index/components/conversation/ConversationList.vue deleted file mode 100644 index 54940f8..0000000 --- a/src/views/ai/chat/index/components/conversation/ConversationList.vue +++ /dev/null @@ -1,472 +0,0 @@ -<!-- AI 瀵硅瘽 --> -<template> - <el-aside width="260px" class="conversation-container h-100%"> - <!-- 宸﹂《閮細瀵硅瘽 --> - <div class="h-100%"> - <el-button class="w-1/1 btn-new-conversation" type="primary" @click="createConversation"> - <Icon icon="ep:plus" class="mr-5px" /> - 鏂板缓瀵硅瘽 - </el-button> - - <!-- 宸﹂《閮細鎼滅储瀵硅瘽 --> - <el-input - v-model="searchName" - size="large" - class="mt-10px search-input" - placeholder="鎼滅储鍘嗗彶璁板綍" - @keyup="searchConversation" - > - <template #prefix> - <Icon icon="ep:search" /> - </template> - </el-input> - - <!-- 宸︿腑闂达細瀵硅瘽鍒楄〃 --> - <div class="conversation-list"> - <!-- 鎯呭喌涓�锛氬姞杞戒腑 --> - <el-empty v-if="loading" description="." :v-loading="loading" /> - <!-- 鎯呭喌浜岋細鎸夌収 group 鍒嗙粍锛屽睍绀鸿亰澶╀細璇� list 鍒楄〃 --> - <div v-for="conversationKey in Object.keys(conversationMap)" :key="conversationKey"> - <div - class="conversation-item classify-title" - v-if="conversationMap[conversationKey].length" - > - <el-text class="mx-1" size="small" tag="b">{{ conversationKey }}</el-text> - </div> - <div - class="conversation-item" - v-for="conversation in conversationMap[conversationKey]" - :key="conversation.id" - @click="handleConversationClick(conversation.id)" - @mouseover="hoverConversationId = conversation.id" - @mouseout="hoverConversationId = ''" - > - <div - :class=" - conversation.id === activeConversationId ? 'conversation active' : 'conversation' - " - > - <div class="title-wrapper"> - <img class="avatar" :src="conversation.roleAvatar || roleAvatarDefaultImg" /> - <span class="title">{{ conversation.title }}</span> - </div> - <div class="button-wrapper" v-show="hoverConversationId === conversation.id"> - <el-button class="btn" link @click.stop="handleTop(conversation)"> - <el-icon title="缃《" v-if="!conversation.pinned"><Top /></el-icon> - <el-icon title="缃《" v-if="conversation.pinned"><Bottom /></el-icon> - </el-button> - <el-button class="btn" link @click.stop="updateConversationTitle(conversation)"> - <el-icon title="缂栬緫"> - <Icon icon="ep:edit" /> - </el-icon> - </el-button> - <el-button class="btn" link @click.stop="deleteChatConversation(conversation)"> - <el-icon title="鍒犻櫎瀵硅瘽"> - <Icon icon="ep:delete" /> - </el-icon> - </el-button> - </div> - </div> - </div> - </div> - <!-- 搴曢儴鍗犱綅 --> - <div class="h-160px w-100%"></div> - </div> - </div> - - <!-- 宸﹀簳閮細宸ュ叿鏍� --> - <div class="tool-box"> - <div @click="handleRoleRepository"> - <Icon icon="ep:user" /> - <el-text size="small">瑙掕壊浠撳簱</el-text> - </div> - <div @click="handleClearConversation"> - <Icon icon="ep:delete" /> - <el-text size="small">娓呯┖鏈疆椤跺璇�</el-text> - </div> - </div> - - <!-- 瑙掕壊浠撳簱鎶藉眽 --> - <el-drawer v-model="roleRepositoryOpen" title="瑙掕壊浠撳簱" size="754px"> - <RoleRepository /> - </el-drawer> - </el-aside> -</template> - -<script setup lang="ts"> -import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation' -import RoleRepository from '../role/RoleRepository.vue' -import { Bottom, Top } from '@element-plus/icons-vue' -import roleAvatarDefaultImg from '@/assets/ai/gpt.svg' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 瀹氫箟灞炴�� -const searchName = ref<string>('') // 瀵硅瘽鎼滅储 -const activeConversationId = ref<number | null>(null) // 閫変腑鐨勫璇濓紝榛樿涓� null -const hoverConversationId = ref<number | null>(null) // 鎮诞涓婂幓鐨勫璇� -const conversationList = ref([] as ChatConversationVO[]) // 瀵硅瘽鍒楄〃 -const conversationMap = ref<any>({}) // 瀵硅瘽鍒嗙粍 (缃《銆佷粖澶┿�佷笁澶╁墠銆佷竴鏄熸湡鍓嶃�佷竴涓湀鍓�) -const loading = ref<boolean>(false) // 鍔犺浇涓� -const loadingTime = ref<any>() // 鍔犺浇涓畾鏃跺櫒 - -// 瀹氫箟缁勪欢 props -const props = defineProps({ - activeId: { - type: String || null, - required: true - } -}) - -// 瀹氫箟閽╁瓙 -const emits = defineEmits([ - 'onConversationCreate', - 'onConversationClick', - 'onConversationClear', - 'onConversationDelete' -]) - -/** 鎼滅储瀵硅瘽 */ -const searchConversation = async (e) => { - // 鎭㈠鏁版嵁 - if (!searchName.value.trim().length) { - conversationMap.value = await getConversationGroupByCreateTime(conversationList.value) - } else { - // 杩囨护 - const filterValues = conversationList.value.filter((item) => { - return item.title.includes(searchName.value.trim()) - }) - conversationMap.value = await getConversationGroupByCreateTime(filterValues) - } -} - -/** 鐐瑰嚮瀵硅瘽 */ -const handleConversationClick = async (id: number) => { - // 杩囨护鍑洪�変腑鐨勫璇� - const filterConversation = conversationList.value.filter((item) => { - return item.id === id - }) - // 鍥炶皟 onConversationClick - // noinspection JSVoidFunctionReturnValueUsed - const success = emits('onConversationClick', filterConversation[0]) - // 鍒囨崲瀵硅瘽 - if (success) { - activeConversationId.value = id - } -} - -/** 鑾峰彇瀵硅瘽鍒楄〃 */ -const getChatConversationList = async () => { - try { - // 鍔犺浇涓� - loadingTime.value = setTimeout(() => { - loading.value = true - }, 50) - - // 1.1 鑾峰彇 瀵硅瘽鏁版嵁 - conversationList.value = await ChatConversationApi.getChatConversationMyList() - // 1.2 鎺掑簭 - conversationList.value.sort((a, b) => { - return b.createTime - a.createTime - }) - // 1.3 娌℃湁浠讳綍瀵硅瘽鎯呭喌 - if (conversationList.value.length === 0) { - activeConversationId.value = null - conversationMap.value = {} - return - } - - // 2. 瀵硅瘽鏍规嵁鏃堕棿鍒嗙粍(缃《銆佷粖澶┿�佷竴澶╁墠銆佷笁澶╁墠銆佷竷澶╁墠銆�30 澶╁墠) - conversationMap.value = await getConversationGroupByCreateTime(conversationList.value) - } finally { - // 娓呯悊瀹氭椂鍣� - if (loadingTime.value) { - clearTimeout(loadingTime.value) - } - // 鍔犺浇瀹屾垚 - loading.value = false - } -} - -/** 鎸夌収 creteTime 鍒涘缓鏃堕棿锛岃繘琛屽垎缁� */ -const getConversationGroupByCreateTime = async (list: ChatConversationVO[]) => { - // 鎺掑簭銆佹寚瀹氥�佹椂闂村垎缁�(浠婂ぉ銆佷竴澶╁墠銆佷笁澶╁墠銆佷竷澶╁墠銆�30澶╁墠) - // noinspection NonAsciiCharacters - const groupMap = { - 缃《: [], - 浠婂ぉ: [], - 涓�澶╁墠: [], - 涓夊ぉ鍓�: [], - 涓冨ぉ鍓�: [], - 涓夊崄澶╁墠: [] - } - // 褰撳墠鏃堕棿鐨勬椂闂存埑 - const now = Date.now() - // 瀹氫箟鏃堕棿闂撮殧甯搁噺锛堝崟浣嶏細姣锛� - const oneDay = 24 * 60 * 60 * 1000 - const threeDays = 3 * oneDay - const sevenDays = 7 * oneDay - const thirtyDays = 30 * oneDay - for (const conversation of list) { - // 缃《 - if (conversation.pinned) { - groupMap['缃《'].push(conversation) - continue - } - // 璁$畻鏃堕棿宸紙鍗曚綅锛氭绉掞級 - const diff = now - conversation.createTime - // 鏍规嵁鏃堕棿闂撮殧鍒ゆ柇 - if (diff < oneDay) { - groupMap['浠婂ぉ'].push(conversation) - } else if (diff < threeDays) { - groupMap['涓�澶╁墠'].push(conversation) - } else if (diff < sevenDays) { - groupMap['涓夊ぉ鍓�'].push(conversation) - } else if (diff < thirtyDays) { - groupMap['涓冨ぉ鍓�'].push(conversation) - } else { - groupMap['涓夊崄澶╁墠'].push(conversation) - } - } - return groupMap -} - -/** 鏂板缓瀵硅瘽 */ -const createConversation = async () => { - // 1. 鏂板缓瀵硅瘽 - const conversationId = await ChatConversationApi.createChatConversationMy( - {} as unknown as ChatConversationVO - ) - // 2. 鑾峰彇瀵硅瘽鍐呭 - await getChatConversationList() - // 3. 閫変腑瀵硅瘽 - await handleConversationClick(conversationId) - // 4. 鍥炶皟 - emits('onConversationCreate') -} - -/** 淇敼瀵硅瘽鐨勬爣棰� */ -const updateConversationTitle = async (conversation: ChatConversationVO) => { - // 1. 浜屾纭 - const { value } = await ElMessageBox.prompt('淇敼鏍囬', { - inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 鍒ゆ柇闈炵┖锛屼笖闈炵┖鏍� - inputErrorMessage: '鏍囬涓嶈兘涓虹┖', - inputValue: conversation.title - }) - // 2. 鍙戣捣淇敼 - await ChatConversationApi.updateChatConversationMy({ - id: conversation.id, - title: value - } as ChatConversationVO) - message.success('閲嶅懡鍚嶆垚鍔�') - // 3. 鍒锋柊鍒楄〃 - await getChatConversationList() - // 4. 杩囨护褰撳墠鍒囨崲鐨� - const filterConversationList = conversationList.value.filter((item) => { - return item.id === conversation.id - }) - if (filterConversationList.length > 0) { - // tip锛氶伩鍏嶅垏鎹㈠璇� - if (activeConversationId.value === filterConversationList[0].id) { - emits('onConversationClick', filterConversationList[0]) - } - } -} - -/** 鍒犻櫎鑱婂ぉ瀵硅瘽 */ -const deleteChatConversation = async (conversation: ChatConversationVO) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm(`鏄惁纭鍒犻櫎瀵硅瘽 - ${conversation.title}?`) - // 鍙戣捣鍒犻櫎 - await ChatConversationApi.deleteChatConversationMy(conversation.id) - message.success('瀵硅瘽宸插垹闄�') - // 鍒锋柊鍒楄〃 - await getChatConversationList() - // 鍥炶皟 - emits('onConversationDelete', conversation) - } catch {} -} - -/** 娓呯┖瀵硅瘽 */ -const handleClearConversation = async () => { - try { - await message.confirm('纭鍚庡璇濅細鍏ㄩ儴娓呯┖锛岀疆椤剁殑瀵硅瘽闄ゅ銆�') - await ChatConversationApi.deleteChatConversationMyByUnpinned() - ElMessage({ - message: '鎿嶄綔鎴愬姛!', - type: 'success' - }) - // 娓呯┖ 瀵硅瘽 鍜� 瀵硅瘽鍐呭 - activeConversationId.value = null - // 鑾峰彇 瀵硅瘽鍒楄〃 - await getChatConversationList() - // 鍥炶皟 鏂规硶 - emits('onConversationClear') - } catch {} -} - -/** 瀵硅瘽缃《 */ -const handleTop = async (conversation: ChatConversationVO) => { - // 鏇存柊瀵硅瘽缃《 - conversation.pinned = !conversation.pinned - await ChatConversationApi.updateChatConversationMy(conversation) - // 鍒锋柊瀵硅瘽 - await getChatConversationList() -} - -// ============ 瑙掕壊浠撳簱 ============ - -/** 瑙掕壊浠撳簱鎶藉眽 */ -const roleRepositoryOpen = ref<boolean>(false) // 瑙掕壊浠撳簱鏄惁鎵撳紑 -const handleRoleRepository = async () => { - roleRepositoryOpen.value = !roleRepositoryOpen.value -} - -/** 鐩戝惉閫変腑鐨勫璇� */ -const { activeId } = toRefs(props) -watch(activeId, async (newValue, oldValue) => { - activeConversationId.value = newValue as string -}) - -// 瀹氫箟 public 鏂规硶 -defineExpose({ createConversation }) - -/** 鍒濆鍖� */ -onMounted(async () => { - // 鑾峰彇 瀵硅瘽鍒楄〃 - await getChatConversationList() - // 榛樿閫変腑 - if (props.activeId) { - activeConversationId.value = props.activeId - } else { - // 棣栨榛樿閫変腑绗竴涓� - if (conversationList.value.length) { - activeConversationId.value = conversationList.value[0].id - // 鍥炶皟 onConversationClick - await emits('onConversationClick', conversationList.value[0]) - } - } -}) -</script> - -<style scoped lang="scss"> -.conversation-container { - position: relative; - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 10px 10px 0; - overflow: hidden; - - .btn-new-conversation { - padding: 18px 0; - } - - .search-input { - margin-top: 20px; - } - - .conversation-list { - overflow: auto; - height: 100%; - - .classify-title { - padding-top: 10px; - } - - .conversation-item { - margin-top: 5px; - } - - .conversation { - display: flex; - flex-direction: row; - justify-content: space-between; - flex: 1; - padding: 0 5px; - cursor: pointer; - border-radius: 5px; - align-items: center; - line-height: 30px; - - &.active { - background-color: #e6e6e6; - - .button { - display: inline-block; - } - } - - .title-wrapper { - display: flex; - flex-direction: row; - align-items: center; - } - - .title { - padding: 2px 10px; - max-width: 220px; - font-size: 14px; - font-weight: 400; - color: rgba(0, 0, 0, 0.77); - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .avatar { - width: 25px; - height: 25px; - border-radius: 5px; - display: flex; - flex-direction: row; - justify-items: center; - } - - // 瀵硅瘽缂栬緫銆佸垹闄� - .button-wrapper { - right: 2px; - display: flex; - flex-direction: row; - justify-items: center; - color: #606266; - - .btn { - margin: 0; - } - } - } - } - - // 瑙掕壊浠撳簱銆佹竻绌烘湭璁剧疆瀵硅瘽 - .tool-box { - position: absolute; - bottom: 0; - left: 0; - right: 0; - //width: 100%; - padding: 0 20px; - background-color: #f4f4f4; - box-shadow: 0 0 1px 1px rgba(228, 228, 228, 0.8); - line-height: 35px; - display: flex; - justify-content: space-between; - align-items: center; - color: var(--el-text-color); - - > div { - display: flex; - align-items: center; - color: #606266; - padding: 0; - margin: 0; - cursor: pointer; - - > span { - margin-left: 5px; - } - } - } -} -</style> diff --git a/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue b/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue deleted file mode 100644 index bff094f..0000000 --- a/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue +++ /dev/null @@ -1,145 +0,0 @@ -<template> - <Dialog title="璁惧畾" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="130px" - v-loading="formLoading" - > - <el-form-item label="瑙掕壊璁惧畾" prop="systemMessage"> - <el-input - type="textarea" - v-model="formData.systemMessage" - rows="4" - placeholder="璇疯緭鍏ヨ鑹茶瀹�" - /> - </el-form-item> - <el-form-item label="妯″瀷" prop="modelId"> - <el-select v-model="formData.modelId" placeholder="璇烽�夋嫨妯″瀷"> - <el-option - v-for="chatModel in chatModelList" - :key="chatModel.id" - :label="chatModel.name" - :value="chatModel.id" - /> - </el-select> - </el-form-item> - <el-form-item label="娓╁害鍙傛暟" prop="temperature"> - <el-input-number - v-model="formData.temperature" - placeholder="璇疯緭鍏ユ俯搴﹀弬鏁�" - :min="0" - :max="2" - :precision="2" - /> - </el-form-item> - <el-form-item label="鍥炲鏁� Token 鏁�" prop="maxTokens"> - <el-input-number - v-model="formData.maxTokens" - placeholder="璇疯緭鍏ュ洖澶嶆暟 Token 鏁�" - :min="0" - :max="4096" - /> - </el-form-item> - <el-form-item label="涓婁笅鏂囨暟閲�" prop="maxContexts"> - <el-input-number - v-model="formData.maxContexts" - placeholder="璇疯緭鍏ヤ笂涓嬫枃鏁伴噺" - :min="0" - :max="20" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { CommonStatusEnum } from '@/utils/constants' -import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' -import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation' - -/** AI 鑱婂ぉ瀵硅瘽鐨勬洿鏂拌〃鍗� */ -defineOptions({ name: 'ChatConversationUpdateForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - systemMessage: undefined, - modelId: undefined, - temperature: undefined, - maxTokens: undefined, - maxContexts: undefined -}) -const formRules = reactive({ - modelId: [{ required: true, message: '妯″瀷涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - temperature: [{ required: true, message: '娓╁害鍙傛暟涓嶈兘涓虹┖', trigger: 'blur' }], - maxTokens: [{ required: true, message: '鍥炲鏁� Token 鏁颁笉鑳戒负绌�', trigger: 'blur' }], - maxContexts: [{ required: true, message: '涓婁笅鏂囨暟閲忎笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const chatModelList = ref([] as ChatModelVO[]) // 鑱婂ぉ妯″瀷鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = await ChatConversationApi.getChatConversationMy(id) - formData.value = Object.keys(formData.value).reduce((obj, key) => { - if (data.hasOwnProperty(key)) { - obj[key] = data[key] - } - return obj - }, {}) - } finally { - formLoading.value = false - } - } - // 鑾峰緱涓嬫媺鏁版嵁 - chatModelList.value = await ChatModelApi.getChatModelSimpleList(CommonStatusEnum.ENABLE) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ChatConversationVO - await ChatConversationApi.updateChatConversationMy(data) - message.success('瀵硅瘽閰嶇疆宸叉洿鏂�') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - systemMessage: undefined, - modelId: undefined, - temperature: undefined, - maxTokens: undefined, - maxContexts: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/ai/chat/index/components/message/MessageList.vue b/src/views/ai/chat/index/components/message/MessageList.vue deleted file mode 100644 index 2cc8407..0000000 --- a/src/views/ai/chat/index/components/message/MessageList.vue +++ /dev/null @@ -1,282 +0,0 @@ -<template> - <div ref="messageContainer" class="h-100% overflow-y-auto relative"> - <div class="chat-list" v-for="(item, index) in list" :key="index"> - <!-- 闈犲乏 message锛歴ystem銆乤ssistant 绫诲瀷 --> - <div class="left-message message-item" v-if="item.type !== 'user'"> - <div class="avatar"> - <el-avatar :src="roleAvatar" /> - </div> - <div class="message"> - <div> - <el-text class="time">{{ formatDate(item.createTime) }}</el-text> - </div> - <div class="left-text-container" ref="markdownViewRef"> - <MarkdownView class="left-text" :content="item.content" /> - </div> - <div class="left-btns"> - <el-button class="btn-cus" link @click="copyContent(item.content)"> - <img class="btn-image" src="@/assets/ai/copy.svg" /> - </el-button> - <el-button v-if="item.id > 0" class="btn-cus" link @click="onDelete(item.id)"> - <img class="btn-image h-17px" src="@/assets/ai/delete.svg" /> - </el-button> - </div> - </div> - </div> - <!-- 闈犲彸 message锛歶ser 绫诲瀷 --> - <div class="right-message message-item" v-if="item.type === 'user'"> - <div class="avatar"> - <el-avatar :src="userAvatar" /> - </div> - <div class="message"> - <div> - <el-text class="time">{{ formatDate(item.createTime) }}</el-text> - </div> - <div class="right-text-container"> - <div class="right-text">{{ item.content }}</div> - </div> - <div class="right-btns"> - <el-button class="btn-cus" link @click="copyContent(item.content)"> - <img class="btn-image" src="@/assets/ai/copy.svg" /> - </el-button> - <el-button class="btn-cus" link @click="onDelete(item.id)"> - <img class="btn-image h-17px mr-12px" src="@/assets/ai/delete.svg" /> - </el-button> - <el-button class="btn-cus" link @click="onRefresh(item)"> - <el-icon size="17"><RefreshRight /></el-icon> - </el-button> - <el-button class="btn-cus" link @click="onEdit(item)"> - <el-icon size="17"><Edit /></el-icon> - </el-button> - </div> - </div> - </div> - </div> - </div> - <!-- 鍥炲埌搴曢儴 --> - <div v-if="isScrolling" class="to-bottom" @click="handleGoBottom"> - <el-button :icon="ArrowDownBold" circle /> - </div> -</template> -<script setup lang="ts"> -import { PropType } from 'vue' -import { formatDate } from '@/utils/formatTime' -import MarkdownView from '@/components/MarkdownView/index.vue' -import { useClipboard } from '@vueuse/core' -import { ArrowDownBold, Edit, RefreshRight } from '@element-plus/icons-vue' -import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message' -import { ChatConversationVO } from '@/api/ai/chat/conversation' -import { useUserStore } from '@/store/modules/user' -import userAvatarDefaultImg from '@/assets/imgs/avatar.gif' -import roleAvatarDefaultImg from '@/assets/ai/gpt.svg' - -const message = useMessage() // 娑堟伅寮圭獥 -const { copy } = useClipboard() // 鍒濆鍖� copy 鍒扮矘璐存澘 -const userStore = useUserStore() - -// 鍒ゆ柇鈥滄秷鎭垪琛ㄢ�濇粴鍔ㄧ殑浣嶇疆(鐢ㄤ簬鍒ゆ柇鏄惁闇�瑕佹粴鍔ㄥ埌娑堟伅鏈�涓嬫柟) -const messageContainer: any = ref(null) -const isScrolling = ref(false) //鐢ㄤ簬鍒ゆ柇鐢ㄦ埛鏄惁鍦ㄦ粴鍔� - -const userAvatar = computed(() => userStore.user.avatar ?? userAvatarDefaultImg) -const roleAvatar = computed(() => props.conversation.roleAvatar ?? roleAvatarDefaultImg) - -// 瀹氫箟 props -const props = defineProps({ - conversation: { - type: Object as PropType<ChatConversationVO>, - required: true - }, - list: { - type: Array as PropType<ChatMessageVO[]>, - required: true - } -}) - -const { list } = toRefs(props) // 娑堟伅鍒楄〃 - -const emits = defineEmits(['onDeleteSuccess', 'onRefresh', 'onEdit']) // 瀹氫箟 emits - -// ============ 澶勭悊瀵硅瘽婊氬姩 ============== - -/** 婊氬姩鍒板簳閮� */ -const scrollToBottom = async (isIgnore?: boolean) => { - // 娉ㄦ剰瑕佷娇鐢� nextTick 浠ュ厤鑾峰彇涓嶅埌 dom - await nextTick() - if (isIgnore || !isScrolling.value) { - messageContainer.value.scrollTop = - messageContainer.value.scrollHeight - messageContainer.value.offsetHeight - } -} - -function handleScroll() { - const scrollContainer = messageContainer.value - const scrollTop = scrollContainer.scrollTop - const scrollHeight = scrollContainer.scrollHeight - const offsetHeight = scrollContainer.offsetHeight - if (scrollTop + offsetHeight < scrollHeight - 100) { - // 鐢ㄦ埛寮�濮嬫粴鍔ㄥ苟鍦ㄦ渶搴曢儴涔嬩笂锛屽彇娑堜繚鎸佸湪鏈�搴曢儴鐨勬晥鏋� - isScrolling.value = true - } else { - // 鐢ㄦ埛鍋滄婊氬姩骞舵粴鍔ㄥ埌鏈�搴曢儴锛屽紑鍚繚鎸佸埌鏈�搴曢儴鐨勬晥鏋� - isScrolling.value = false - } -} - -/** 鍥炲埌搴曢儴 */ -const handleGoBottom = async () => { - const scrollContainer = messageContainer.value - scrollContainer.scrollTop = scrollContainer.scrollHeight -} - -/** 鍥炲埌椤堕儴 */ -const handlerGoTop = async () => { - const scrollContainer = messageContainer.value - scrollContainer.scrollTop = 0 -} - -defineExpose({ scrollToBottom, handlerGoTop }) // 鎻愪緵鏂规硶缁� parent 璋冪敤 - -// ============ 澶勭悊娑堟伅鎿嶄綔 ============== - -/** 澶嶅埗 */ -const copyContent = async (content) => { - await copy(content) - message.success('澶嶅埗鎴愬姛锛�') -} - -/** 鍒犻櫎 */ -const onDelete = async (id) => { - // 鍒犻櫎 message - await ChatMessageApi.deleteChatMessage(id) - message.success('鍒犻櫎鎴愬姛锛�') - // 鍥炶皟 - emits('onDeleteSuccess') -} - -/** 鍒锋柊 */ -const onRefresh = async (message: ChatMessageVO) => { - emits('onRefresh', message) -} - -/** 缂栬緫 */ -const onEdit = async (message: ChatMessageVO) => { - emits('onEdit', message) -} - -/** 鍒濆鍖� */ -onMounted(async () => { - messageContainer.value.addEventListener('scroll', handleScroll) -}) -</script> - -<style scoped lang="scss"> -.message-container { - position: relative; - overflow-y: scroll; -} - -// 涓棿 -.chat-list { - display: flex; - flex-direction: column; - overflow-y: hidden; - padding: 0 20px; - .message-item { - margin-top: 50px; - } - - .left-message { - display: flex; - flex-direction: row; - } - - .right-message { - display: flex; - flex-direction: row-reverse; - justify-content: flex-start; - } - - .message { - display: flex; - flex-direction: column; - text-align: left; - margin: 0 15px; - - .time { - text-align: left; - line-height: 30px; - } - - .left-text-container { - position: relative; - display: flex; - flex-direction: column; - overflow-wrap: break-word; - background-color: rgba(228, 228, 228, 0.8); - box-shadow: 0 0 0 1px rgba(228, 228, 228, 0.8); - border-radius: 10px; - padding: 10px 10px 5px 10px; - - .left-text { - color: #393939; - font-size: 0.95rem; - } - } - - .right-text-container { - display: flex; - flex-direction: row-reverse; - - .right-text { - font-size: 0.95rem; - color: #fff; - display: inline; - background-color: #267fff; - box-shadow: 0 0 0 1px #267fff; - border-radius: 10px; - padding: 10px; - width: auto; - overflow-wrap: break-word; - white-space: pre-wrap; - } - } - - .left-btns { - display: flex; - flex-direction: row; - margin-top: 8px; - } - - .right-btns { - display: flex; - flex-direction: row-reverse; - margin-top: 8px; - } - } - - // 澶嶅埗銆佸垹闄ゆ寜閽� - .btn-cus { - display: flex; - background-color: transparent; - align-items: center; - - .btn-image { - height: 20px; - } - } - - .btn-cus:hover { - cursor: pointer; - background-color: #f6f6f6; - } -} - -// 鍥炲埌搴曢儴 -.to-bottom { - position: absolute; - z-index: 1000; - bottom: 0; - right: 50%; -} -</style> diff --git a/src/views/ai/chat/index/components/message/MessageListEmpty.vue b/src/views/ai/chat/index/components/message/MessageListEmpty.vue deleted file mode 100644 index b042fd6..0000000 --- a/src/views/ai/chat/index/components/message/MessageListEmpty.vue +++ /dev/null @@ -1,83 +0,0 @@ -<!-- 娑堟伅鍒楄〃涓虹┖鏃讹紝灞曠ず prompt 鍒楄〃 --> -<template> - <div class="chat-empty"> - <!-- title --> - <div class="center-container"> - <div class="title">鑺嬮亾 AI</div> - <div class="role-list"> - <div - class="role-item" - v-for="prompt in promptList" - :key="prompt.prompt" - @click="handlerPromptClick(prompt)" - > - {{ prompt.prompt }} - </div> - </div> - </div> - </div> -</template> -<script setup lang="ts"> -const promptList = [ - { - prompt: '浠婂ぉ姘旀�庝箞鏍�?' - }, - { - prompt: '鍐欎竴棣栧ソ鍚殑璇楁瓕?' - } -] // prompt 鍒楄〃 - -const emits = defineEmits(['onPrompt']) - -/** 閫変腑 prompt 鐐瑰嚮 */ -const handlerPromptClick = async ({ prompt }) => { - emits('onPrompt', prompt) -} -</script> -<style scoped lang="scss"> -.chat-empty { - position: relative; - display: flex; - flex-direction: row; - justify-content: center; - width: 100%; - height: 100%; - - .center-container { - display: flex; - flex-direction: column; - justify-content: center; - - .title { - font-size: 28px; - font-weight: bold; - text-align: center; - } - - .role-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: center; - justify-content: center; - width: 460px; - margin-top: 20px; - - .role-item { - display: flex; - justify-content: center; - width: 180px; - line-height: 50px; - border: 1px solid #e4e4e4; - border-radius: 10px; - margin: 10px; - cursor: pointer; - } - - .role-item:hover { - background-color: rgba(243, 243, 243, 0.73); - } - } - } -} -</style> diff --git a/src/views/ai/chat/index/components/message/MessageLoading.vue b/src/views/ai/chat/index/components/message/MessageLoading.vue deleted file mode 100644 index f3198cb..0000000 --- a/src/views/ai/chat/index/components/message/MessageLoading.vue +++ /dev/null @@ -1,15 +0,0 @@ -<!-- message 鍔犺浇椤甸潰 --> -<template> - <div class="message-loading" > - <el-skeleton animated /> - </div> -</template> - -<script setup lang="ts"> - -</script> -<style scoped lang="scss"> -.message-loading { - padding: 30px 30px; -} -</style> diff --git a/src/views/ai/chat/index/components/message/MessageNewConversation.vue b/src/views/ai/chat/index/components/message/MessageNewConversation.vue deleted file mode 100644 index 40c3107..0000000 --- a/src/views/ai/chat/index/components/message/MessageNewConversation.vue +++ /dev/null @@ -1,46 +0,0 @@ -<!-- 鏃犺亰澶╁璇濇椂锛屽湪 message 鍖哄煙锛屽彲浠ユ柊澧炲璇� --> -<template> - <div class="new-chat"> - <div class="box-center"> - <div class="tip">鐐瑰嚮涓嬫柟鎸夐挳锛屽紑濮嬩綘鐨勫璇濆惂</div> - <div class="btns"> - <el-button type="primary" round @click="handlerNewChat">鏂板缓瀵硅瘽</el-button> - </div> - </div> - </div> -</template> -<script setup lang="ts"> -const emits = defineEmits(['onNewConversation']) - -/** 鏂板缓 conversation 鑱婂ぉ瀵硅瘽 */ -const handlerNewChat = () => { - emits('onNewConversation') -} -</script> -<style scoped lang="scss"> -.new-chat { - display: flex; - flex-direction: row; - justify-content: center; - width: 100%; - height: 100%; - - .box-center { - display: flex; - flex-direction: column; - justify-content: center; - - .tip { - font-size: 14px; - color: #858585; - } - - .btns { - display: flex; - flex-direction: row; - justify-content: center; - margin-top: 20px; - } - } -} -</style> diff --git a/src/views/ai/chat/index/components/role/RoleCategoryList.vue b/src/views/ai/chat/index/components/role/RoleCategoryList.vue deleted file mode 100644 index c02126d..0000000 --- a/src/views/ai/chat/index/components/role/RoleCategoryList.vue +++ /dev/null @@ -1,53 +0,0 @@ -<template> - <div class="category-list"> - <div class="category" v-for="category in categoryList" :key="category"> - <el-button - plain - round - size="small" - :type="category === active ? 'primary' : ''" - @click="handleCategoryClick(category)" - > - {{ category }} - </el-button> - </div> - </div> -</template> -<script setup lang="ts"> -import { PropType } from 'vue' - -// 瀹氫箟灞炴�� -defineProps({ - categoryList: { - type: Array as PropType<string[]>, - required: true - }, - active: { - type: String, - required: false, - default: '鍏ㄩ儴' - } -}) - -// 瀹氫箟鍥炶皟 -const emits = defineEmits(['onCategoryClick']) - -/** 澶勭悊鍒嗙被鐐瑰嚮浜嬩欢 */ -const handleCategoryClick = async (category: string) => { - emits('onCategoryClick', category) -} -</script> -<style scoped lang="scss"> -.category-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: center; - - .category { - display: flex; - flex-direction: row; - margin-right: 10px; - } -} -</style> diff --git a/src/views/ai/chat/index/components/role/RoleHeader.vue b/src/views/ai/chat/index/components/role/RoleHeader.vue deleted file mode 100644 index 17b1693..0000000 --- a/src/views/ai/chat/index/components/role/RoleHeader.vue +++ /dev/null @@ -1,48 +0,0 @@ -<!-- header --> -<template> - <el-header class="chat-header"> - <div class="title"> - {{ title }} - </div> - <div class="title-right"> - <slot></slot> - </div> - </el-header> -</template> - -<script setup lang="ts"> -// 璁剧疆缁勪欢灞炴�� -defineProps({ - title: { - type: String, - required: true - } -}) -</script> - -<style scoped lang="scss"> -.chat-header { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - padding: 0 10px; - white-space: nowrap; - text-overflow: ellipsis; - background-color: #ececec; - width: 100%; - - .title { - font-size: 20px; - font-weight: bold; - overflow: hidden; - color: #3e3e3e; - max-width: 220px; - } - - .title-right { - display: flex; - flex-direction: row; - } -} -</style> diff --git a/src/views/ai/chat/index/components/role/RoleList.vue b/src/views/ai/chat/index/components/role/RoleList.vue deleted file mode 100644 index b148b22..0000000 --- a/src/views/ai/chat/index/components/role/RoleList.vue +++ /dev/null @@ -1,174 +0,0 @@ -<template> - <div class="card-list" ref="tabsRef" @scroll="handleTabsScroll"> - <div class="card-item" v-for="role in roleList" :key="role.id"> - <el-card class="card" body-class="card-body"> - <!-- 鏇村鎿嶄綔 --> - <div class="more-container" v-if="showMore"> - <el-dropdown @command="handleMoreClick"> - <span class="el-dropdown-link"> - <el-button type="text"> - <el-icon><More /></el-icon> - </el-button> - </span> - <template #dropdown> - <el-dropdown-menu> - <el-dropdown-item :command="['edit', role]"> - <Icon icon="ep:edit" color="#787878" />缂栬緫 - </el-dropdown-item> - <el-dropdown-item :command="['delete', role]" style="color: red"> - <Icon icon="ep:delete" color="red" />鍒犻櫎 - </el-dropdown-item> - </el-dropdown-menu> - </template> - </el-dropdown> - </div> - <!-- 瑙掕壊淇℃伅 --> - <div> - <img class="avatar" :src="role.avatar" /> - </div> - <div class="right-container"> - <div class="content-container"> - <div class="title">{{ role.name }}</div> - <div class="description">{{ role.description }}</div> - </div> - <div class="btn-container"> - <el-button type="primary" size="small" @click="handleUseClick(role)">浣跨敤</el-button> - </div> - </div> - </el-card> - </div> - </div> -</template> - -<script setup lang="ts"> -import {ChatRoleVO} from '@/api/ai/model/chatRole' -import {PropType, ref} from 'vue' -import {More} from '@element-plus/icons-vue' - -const tabsRef = ref<any>() // tabs ref - -// 瀹氫箟灞炴�� -const props = defineProps({ - loading: { - type: Boolean, - required: true - }, - roleList: { - type: Array as PropType<ChatRoleVO[]>, - required: true - }, - showMore: { - type: Boolean, - required: false, - default: false - } -}) - -// 瀹氫箟閽╁瓙 -const emits = defineEmits(['onDelete', 'onEdit', 'onUse', 'onPage']) - -/** 鎿嶄綔锛氱紪杈戙�佸垹闄� */ -const handleMoreClick = async (data) => { - const type = data[0] - const role = data[1] - if (type === 'delete') { - emits('onDelete', role) - } else { - emits('onEdit', role) - } -} - -/** 閫変腑 */ -const handleUseClick = (role) => { - emits('onUse', role) -} - -/** 婊氬姩 */ -const handleTabsScroll = async () => { - if (tabsRef.value) { - const { scrollTop, scrollHeight, clientHeight } = tabsRef.value - if (scrollTop + clientHeight >= scrollHeight - 20 && !props.loading) { - await emits('onPage') - } - } -} -</script> - -<style lang="scss"> -// 閲嶅啓 card 缁勪欢 body 鏍峰紡 -.card-body { - max-width: 240px; - width: 240px; - padding: 15px 15px 10px 15px; - - display: flex; - flex-direction: row; - justify-content: flex-start; - position: relative; -} -</style> -<style scoped lang="scss"> -// 鍗$墖鍒楄〃 -.card-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - position: relative; - height: 100%; - overflow: auto; - padding: 0px 25px; - padding-bottom: 140px; - align-items: start; - align-content: flex-start; - justify-content: start; - - .card { - display: inline-block; - margin-right: 20px; - border-radius: 10px; - margin-bottom: 20px; - position: relative; - - .more-container { - position: absolute; - top: 0; - right: 12px; - } - - .avatar { - width: 40px; - height: 40px; - border-radius: 10px; - overflow: hidden; - } - - .right-container { - margin-left: 10px; - width: 100%; - //height: 100px; - - .content-container { - height: 85px; - - .title { - font-size: 18px; - font-weight: bold; - color: #3e3e3e; - } - - .description { - margin-top: 10px; - font-size: 14px; - color: #6a6a6a; - } - } - - .btn-container { - display: flex; - flex-direction: row-reverse; - margin-top: 2px; - } - } - } -} -</style> diff --git a/src/views/ai/chat/index/components/role/RoleRepository.vue b/src/views/ai/chat/index/components/role/RoleRepository.vue deleted file mode 100644 index 246dcb4..0000000 --- a/src/views/ai/chat/index/components/role/RoleRepository.vue +++ /dev/null @@ -1,289 +0,0 @@ -<!-- chat 瑙掕壊浠撳簱 --> -<template> - <el-container class="role-container"> - <ChatRoleForm ref="formRef" @success="handlerAddRoleSuccess" /> - <!-- header --> - <RoleHeader title="瑙掕壊浠撳簱" class="relative" /> - <!-- main --> - <el-main class="role-main"> - <div class="search-container"> - <!-- 鎼滅储鎸夐挳 --> - <el-input - :loading="loading" - v-model="search" - class="search-input" - size="default" - placeholder="璇疯緭鍏ユ悳绱㈢殑鍐呭" - :suffix-icon="Search" - @change="getActiveTabsRole" - /> - <el-button - v-if="activeTab == 'my-role'" - type="primary" - @click="handlerAddRole" - class="ml-20px" - > - <Icon icon="ep:user" style="margin-right: 5px;" /> - 娣诲姞瑙掕壊 - </el-button> - </div> - <!-- tabs --> - <el-tabs v-model="activeTab" class="tabs" @tab-click="handleTabsClick"> - <el-tab-pane class="role-pane" label="鎴戠殑瑙掕壊" name="my-role"> - <RoleList - :loading="loading" - :role-list="myRoleList" - :show-more="true" - @on-delete="handlerCardDelete" - @on-edit="handlerCardEdit" - @on-use="handlerCardUse" - @on-page="handlerCardPage('my')" - class="mt-20px" - /> - </el-tab-pane> - <el-tab-pane label="鍏叡瑙掕壊" name="public-role"> - <RoleCategoryList - class="role-category-list" - :category-list="categoryList" - :active="activeCategory" - @on-category-click="handlerCategoryClick" - /> - <RoleList - :role-list="publicRoleList" - @on-delete="handlerCardDelete" - @on-edit="handlerCardEdit" - @on-use="handlerCardUse" - @on-page="handlerCardPage('public')" - class="mt-20px" - loading - /> - </el-tab-pane> - </el-tabs> - </el-main> - </el-container> -</template> - -<script setup lang="ts"> -import {ref} from 'vue' -import RoleHeader from './RoleHeader.vue' -import RoleList from './RoleList.vue' -import ChatRoleForm from '@/views/ai/model/chatRole/ChatRoleForm.vue' -import RoleCategoryList from './RoleCategoryList.vue' -import {ChatRoleApi, ChatRolePageReqVO, ChatRoleVO} from '@/api/ai/model/chatRole' -import {ChatConversationApi, ChatConversationVO} from '@/api/ai/chat/conversation' -import {Search} from '@element-plus/icons-vue' -import {TabsPaneContext} from 'element-plus' - -const router = useRouter() // 璺敱瀵硅薄 - -// 灞炴�у畾涔� -const loading = ref<boolean>(false) // 鍔犺浇涓� -const activeTab = ref<string>('my-role') // 閫変腑鐨勮鑹� Tab -const search = ref<string>('') // 鍔犺浇涓� -const myRoleParams = reactive({ - pageNo: 1, - pageSize: 50 -}) -const myRoleList = ref<ChatRoleVO[]>([]) // my 鍒嗛〉澶у皬 -const publicRoleParams = reactive({ - pageNo: 1, - pageSize: 50 -}) -const publicRoleList = ref<ChatRoleVO[]>([]) // public 鍒嗛〉澶у皬 -const activeCategory = ref<string>('鍏ㄩ儴') // 閫夋嫨涓殑鍒嗙被 -const categoryList = ref<string[]>([]) // 瑙掕壊鍒嗙被绫诲埆 - -/** tabs 鐐瑰嚮 */ -const handleTabsClick = async (tab: TabsPaneContext) => { - // 璁剧疆鍒囨崲鐘舵�� - activeTab.value = tab.paneName + '' - // 鍒囨崲鐨勬椂鍊欓噸鏂板姞杞芥暟鎹� - await getActiveTabsRole() -} - -/** 鑾峰彇 my role 鎴戠殑瑙掕壊 */ -const getMyRole = async (append?: boolean) => { - const params: ChatRolePageReqVO = { - ...myRoleParams, - name: search.value, - publicStatus: false - } - const { list } = await ChatRoleApi.getMyPage(params) - if (append) { - myRoleList.value.push.apply(myRoleList.value, list) - } else { - myRoleList.value = list - } -} - -/** 鑾峰彇 public role 鍏叡瑙掕壊 */ -const getPublicRole = async (append?: boolean) => { - const params: ChatRolePageReqVO = { - ...publicRoleParams, - category: activeCategory.value === '鍏ㄩ儴' ? '' : activeCategory.value, - name: search.value, - publicStatus: true - } - const { total, list } = await ChatRoleApi.getMyPage(params) - if (append) { - publicRoleList.value.push.apply(publicRoleList.value, list) - } else { - publicRoleList.value = list - } -} - -/** 鑾峰彇閫変腑鐨� tabs 瑙掕壊 */ -const getActiveTabsRole = async () => { - if (activeTab.value === 'my-role') { - myRoleParams.pageNo = 1 - await getMyRole() - } else { - publicRoleParams.pageNo = 1 - await getPublicRole() - } -} - -/** 鑾峰彇瑙掕壊鍒嗙被鍒楄〃 */ -const getRoleCategoryList = async () => { - categoryList.value = ['鍏ㄩ儴', ...(await ChatRoleApi.getCategoryList())] -} - -/** 澶勭悊鍒嗙被鐐瑰嚮 */ -const handlerCategoryClick = async (category: string) => { - // 鍒囨崲閫夋嫨鐨勫垎绫� - activeCategory.value = category - // 绛涢�� - await getActiveTabsRole() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const handlerAddRole = async () => { - formRef.value.open('my-create', null, '娣诲姞瑙掕壊') -} -/** 缂栬緫瑙掕壊 */ -const handlerCardEdit = async (role) => { - formRef.value.open('my-update', role.id, '缂栬緫瑙掕壊') -} - -/** 娣诲姞瑙掕壊鎴愬姛 */ -const handlerAddRoleSuccess = async (e) => { - // 鍒锋柊鏁版嵁 - await getActiveTabsRole() -} - -/** 鍒犻櫎瑙掕壊 */ -const handlerCardDelete = async (role) => { - await ChatRoleApi.deleteMy(role.id) - // 鍒锋柊鏁版嵁 - await getActiveTabsRole() -} - -/** 瑙掕壊鍒嗛〉锛氳幏鍙栦笅涓�椤� */ -const handlerCardPage = async (type) => { - try { - loading.value = true - if (type === 'public') { - publicRoleParams.pageNo++ - await getPublicRole(true) - } else { - myRoleParams.pageNo++ - await getMyRole(true) - } - } finally { - loading.value = false - } -} - -/** 閫夋嫨 card 瑙掕壊锛氭柊寤鸿亰澶╁璇� */ -const handlerCardUse = async (role) => { - // 1. 鍒涘缓瀵硅瘽 - const data: ChatConversationVO = { - roleId: role.id - } as unknown as ChatConversationVO - const conversationId = await ChatConversationApi.createChatConversationMy(data) - - // 2. 璺宠浆椤甸潰 - await router.push({ - name: 'AiChat', - query: { - conversationId: conversationId - } - }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - // 鑾峰彇鍒嗙被 - await getRoleCategoryList() - // 鑾峰彇 role 鏁版嵁 - await getActiveTabsRole() -}) -</script> -<!-- 瑕嗙洊 element ui css --> -<style lang="scss"> -.el-tabs__content { - position: relative; - height: 100%; - overflow: hidden; -} -.el-tabs__nav-scroll { - margin: 10px 20px; -} -</style> -<!-- 鏍峰紡 --> -<style scoped lang="scss"> -// 璺熷鍣� -.role-container { - position: absolute; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-color: #ffffff; - overflow: hidden; - display: flex; - flex-direction: column; - - .role-main { - flex: 1; - overflow: hidden; - margin: 0; - padding: 0; - position: relative; - - .search-container { - margin: 20px 20px 0px 20px; - position: absolute; - right: 0; - top: -5px; - z-index: 100; - } - - .search-input { - width: 240px; - } - - .tabs { - position: relative; - height: 100%; - - .role-category-list { - margin: 0 27px; - } - } - - .role-pane { - display: flex; - flex-direction: column; - height: 100%; - overflow-y: auto; - position: relative; - } - } -} -</style> diff --git a/src/views/ai/chat/index/index.vue b/src/views/ai/chat/index/index.vue deleted file mode 100644 index 229b895..0000000 --- a/src/views/ai/chat/index/index.vue +++ /dev/null @@ -1,773 +0,0 @@ -<template> - <el-container class="ai-layout"> - <!-- 宸︿晶锛氬璇濆垪琛� --> - <ConversationList - :active-id="activeConversationId" - ref="conversationListRef" - @onConversationCreate="handleConversationCreateSuccess" - @onConversationClick="handleConversationClick" - @onConversationClear="handleConversationClear" - @onConversationDelete="handlerConversationDelete" - /> - <!-- 鍙充晶锛氬璇濊鎯� --> - <el-container class="detail-container"> - <el-header class="header"> - <div class="title"> - {{ activeConversation?.title ? activeConversation?.title : '瀵硅瘽' }} - <span v-if="activeMessageList.length">({{ activeMessageList.length }})</span> - </div> - <div class="btns" v-if="activeConversation"> - <el-button type="primary" bg plain size="small" @click="openChatConversationUpdateForm"> - <span v-html="activeConversation?.modelName"></span> - <Icon icon="ep:setting" class="ml-10px" /> - </el-button> - <el-button size="small" class="btn" @click="handlerMessageClear"> - <Icon icon="heroicons-outline:archive-box-x-mark" color="#787878" /> - </el-button> - <el-button size="small" class="btn"> - <Icon icon="ep:download" color="#787878" /> - </el-button> - <el-button size="small" class="btn" @click="handleGoTopMessage" > - <Icon icon="ep:top" color="#787878" /> - </el-button> - </div> - </el-header> - - <!-- main锛氭秷鎭垪琛� --> - <el-main class="main-container"> - <div> - <div class="message-container"> - <!-- 鎯呭喌涓�锛氭秷鎭姞杞戒腑 --> - <MessageLoading v-if="activeMessageListLoading" /> - <!-- 鎯呭喌浜岋細鏃犺亰澶╁璇濇椂 --> - <MessageNewConversation - v-if="!activeConversation" - @on-new-conversation="handleConversationCreate" - /> - <!-- 鎯呭喌涓夛細娑堟伅鍒楄〃涓虹┖ --> - <MessageListEmpty - v-if="!activeMessageListLoading && messageList.length === 0 && activeConversation" - @on-prompt="doSendMessage" - /> - <!-- 鎯呭喌鍥涳細娑堟伅鍒楄〃涓嶄负绌� --> - <MessageList - v-if="!activeMessageListLoading && messageList.length > 0" - ref="messageRef" - :conversation="activeConversation" - :list="messageList" - @on-delete-success="handleMessageDelete" - @on-edit="handleMessageEdit" - @on-refresh="handleMessageRefresh" - /> - </div> - </div> - </el-main> - - <!-- 搴曢儴 --> - <el-footer class="footer-container"> - <form class="prompt-from"> - <textarea - class="prompt-input" - v-model="prompt" - @keydown="handleSendByKeydown" - @input="handlePromptInput" - @compositionstart="onCompositionstart" - @compositionend="onCompositionend" - placeholder="闂垜浠讳綍闂...锛圫hift+Enter 鎹㈣锛屾寜涓� Enter 鍙戦�侊級" - ></textarea> - <div class="prompt-btns"> - <div> - <el-switch v-model="enableContext" /> - <span class="ml-5px text-14px text-#8f8f8f">涓婁笅鏂�</span> - </div> - <el-button - type="primary" - size="default" - @click="handleSendByButton" - :loading="conversationInProgress" - v-if="conversationInProgress == false" - > - {{ conversationInProgress ? '杩涜涓�' : '鍙戦��' }} - </el-button> - <el-button - type="danger" - size="default" - @click="stopStream()" - v-if="conversationInProgress == true" - > - 鍋滄 - </el-button> - </div> - </form> - </el-footer> - </el-container> - - <!-- 鏇存柊瀵硅瘽 Form --> - <ConversationUpdateForm - ref="conversationUpdateFormRef" - @success="handleConversationUpdateSuccess" - /> - </el-container> -</template> - -<script setup lang="ts"> -import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message' -import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation' -import ConversationList from './components/conversation/ConversationList.vue' -import ConversationUpdateForm from './components/conversation/ConversationUpdateForm.vue' -import MessageList from './components/message/MessageList.vue' -import MessageListEmpty from './components/message/MessageListEmpty.vue' -import MessageLoading from './components/message/MessageLoading.vue' -import MessageNewConversation from './components/message/MessageNewConversation.vue' -import { Download, Top } from '@element-plus/icons-vue' - -/** AI 鑱婂ぉ瀵硅瘽 鍒楄〃 */ -defineOptions({ name: 'AiChat' }) - -const route = useRoute() // 璺敱 -const message = useMessage() // 娑堟伅寮圭獥 - -// 鑱婂ぉ瀵硅瘽 -const conversationListRef = ref() -const activeConversationId = ref<number | null>(null) // 閫変腑鐨勫璇濈紪鍙� -const activeConversation = ref<ChatConversationVO | null>(null) // 閫変腑鐨� Conversation -const conversationInProgress = ref(false) // 瀵硅瘽鏄惁姝e湪杩涜涓�傜洰鍓嶅彧鏈夈�愬彂閫併�戞秷鎭椂锛屼細鏇存柊涓� true锛岄伩鍏嶅垏鎹㈠璇濄�佸垹闄ゅ璇濈瓑鎿嶄綔 - -// 娑堟伅鍒楄〃 -const messageRef = ref() -const activeMessageList = ref<ChatMessageVO[]>([]) // 閫変腑瀵硅瘽鐨勬秷鎭垪琛� -const activeMessageListLoading = ref<boolean>(false) // activeMessageList 鏄惁姝e湪鍔犺浇涓� -const activeMessageListLoadingTimer = ref<any>() // activeMessageListLoading Timer 瀹氭椂鍣ㄣ�傚鏋滃姞杞介�熷害寰堝揩锛屽氨涓嶈繘鍏ュ姞杞戒腑 -// 娑堟伅婊氬姩 -const textSpeed = ref<number>(50) // Typing speed in milliseconds -const textRoleRunning = ref<boolean>(false) // Typing speed in milliseconds - -// 鍙戦�佹秷鎭緭鍏ユ -const isComposing = ref(false) // 鍒ゆ柇鐢ㄦ埛鏄惁鍦ㄨ緭鍏� -const conversationInAbortController = ref<any>() // 瀵硅瘽杩涜涓� abort 鎺у埗鍣�(鎺у埗 stream 瀵硅瘽) -const inputTimeout = ref<any>() // 澶勭悊杈撳叆涓洖杞︾殑瀹氭椂鍣� -const prompt = ref<string>() // prompt -const enableContext = ref<boolean>(true) // 鏄惁寮�鍚笂涓嬫枃 -// 鎺ユ敹 Stream 娑堟伅 -const receiveMessageFullText = ref('') -const receiveMessageDisplayedText = ref('') - -// =========== 銆愯亰澶╁璇濄�戠浉鍏� =========== - -/** 鑾峰彇瀵硅瘽淇℃伅 */ -const getConversation = async (id: number | null) => { - if (!id) { - return - } - const conversation: ChatConversationVO = await ChatConversationApi.getChatConversationMy(id) - if (!conversation) { - return - } - activeConversation.value = conversation - activeConversationId.value = conversation.id -} - -/** - * 鐐瑰嚮鏌愪釜瀵硅瘽 - * - * @param conversation 閫変腑鐨勫璇� - * @return 鏄惁鍒囨崲鎴愬姛 - */ -const handleConversationClick = async (conversation: ChatConversationVO) => { - // 瀵硅瘽杩涜涓紝涓嶅厑璁稿垏鎹� - if (conversationInProgress.value) { - message.alert('瀵硅瘽涓紝涓嶅厑璁稿垏鎹�!') - return false - } - - // 鏇存柊閫変腑鐨勫璇� id - activeConversationId.value = conversation.id - activeConversation.value = conversation - // 鍒锋柊 message 鍒楄〃 - await getMessageList() - // 婊氬姩搴曢儴 - scrollToBottom(true) - // 娓呯┖杈撳叆妗� - prompt.value = '' - return true -} - -/** 鍒犻櫎鏌愪釜瀵硅瘽*/ -const handlerConversationDelete = async (delConversation: ChatConversationVO) => { - // 鍒犻櫎鐨勫璇濆鏋滄槸褰撳墠閫変腑鐨勶紝閭d箞灏遍噸缃� - if (activeConversationId.value === delConversation.id) { - await handleConversationClear() - } -} -/** 娓呯┖閫変腑鐨勫璇� */ -const handleConversationClear = async () => { - // 瀵硅瘽杩涜涓紝涓嶅厑璁稿垏鎹� - if (conversationInProgress.value) { - message.alert('瀵硅瘽涓紝涓嶅厑璁稿垏鎹�!') - return false - } - activeConversationId.value = null - activeConversation.value = null - activeMessageList.value = [] -} - -/** 淇敼鑱婂ぉ瀵硅瘽 */ -const conversationUpdateFormRef = ref() -const openChatConversationUpdateForm = async () => { - conversationUpdateFormRef.value.open(activeConversationId.value) -} -const handleConversationUpdateSuccess = async () => { - // 瀵硅瘽鏇存柊鎴愬姛锛屽埛鏂版渶鏂颁俊鎭� - await getConversation(activeConversationId.value) -} - -/** 澶勭悊鑱婂ぉ瀵硅瘽鐨勫垱寤烘垚鍔� */ -const handleConversationCreate = async () => { - // 鍒涘缓瀵硅瘽 - await conversationListRef.value.createConversation() -} -/** 澶勭悊鑱婂ぉ瀵硅瘽鐨勫垱寤烘垚鍔� */ -const handleConversationCreateSuccess = async () => { - // 鍒涘缓鏂扮殑瀵硅瘽锛屾竻绌鸿緭鍏ユ - prompt.value = '' -} - -// =========== 銆愭秷鎭垪琛ㄣ�戠浉鍏� =========== - -/** 鑾峰彇娑堟伅 message 鍒楄〃 */ -const getMessageList = async () => { - try { - if (activeConversationId.value === null) { - return - } - // Timer 瀹氭椂鍣紝濡傛灉鍔犺浇閫熷害寰堝揩锛屽氨涓嶈繘鍏ュ姞杞戒腑 - activeMessageListLoadingTimer.value = setTimeout(() => { - activeMessageListLoading.value = true - }, 60) - - // 鑾峰彇娑堟伅鍒楄〃 - activeMessageList.value = await ChatMessageApi.getChatMessageListByConversationId( - activeConversationId.value - ) - - // 婊氬姩鍒版渶涓嬮潰 - await nextTick() - await scrollToBottom() - } finally { - // time 瀹氭椂鍣紝濡傛灉鍔犺浇閫熷害寰堝揩锛屽氨涓嶈繘鍏ュ姞杞戒腑 - if (activeMessageListLoadingTimer.value) { - clearTimeout(activeMessageListLoadingTimer.value) - } - // 鍔犺浇缁撴潫 - activeMessageListLoading.value = false - } -} - -/** - * 娑堟伅鍒楄〃 - * - * 鍜� {@link #getMessageList()} 鐨勫樊寮傛槸锛屾妸 systemMessage 鑰冭檻杩涘幓 - */ -const messageList = computed(() => { - if (activeMessageList.value.length > 0) { - return activeMessageList.value - } - // 娌℃湁娑堟伅鏃讹紝濡傛灉鏈� systemMessage 鍒欏睍绀哄畠 - if (activeConversation.value?.systemMessage) { - return [ - { - id: 0, - type: 'system', - content: activeConversation.value.systemMessage - } - ] - } - return [] -}) - -/** 澶勭悊鍒犻櫎 message 娑堟伅 */ -const handleMessageDelete = () => { - if (conversationInProgress.value) { - message.alert('鍥炵瓟涓紝涓嶈兘鍒犻櫎!') - return - } - // 鍒锋柊 message 鍒楄〃 - getMessageList() -} - -/** 澶勭悊 message 娓呯┖ */ -const handlerMessageClear = async () => { - if (!activeConversationId.value) { - return - } - try { - // 纭鎻愮ず - await message.delConfirm('纭娓呯┖瀵硅瘽娑堟伅锛�') - // 娓呯┖瀵硅瘽 - await ChatMessageApi.deleteByConversationId(activeConversationId.value) - // 鍒锋柊 message 鍒楄〃 - activeMessageList.value = [] - } catch {} -} - -/** 鍥炲埌 message 鍒楄〃鐨勯《閮� */ -const handleGoTopMessage = () => { - messageRef.value.handlerGoTop() -} - -// =========== 銆愬彂閫佹秷鎭�戠浉鍏� =========== - -/** 澶勭悊鏉ヨ嚜 keydown 鐨勫彂閫佹秷鎭� */ -const handleSendByKeydown = async (event) => { - // 鍒ゆ柇鐢ㄦ埛鏄惁鍦ㄨ緭鍏� - if (isComposing.value) { - return - } - // 杩涜涓笉鍏佽鍙戦�� - if (conversationInProgress.value) { - return - } - const content = prompt.value?.trim() as string - if (event.key === 'Enter') { - if (event.shiftKey) { - // 鎻掑叆鎹㈣ - prompt.value += '\r\n' - event.preventDefault() // 闃叉榛樿鐨勬崲琛岃涓� - } else { - // 鍙戦�佹秷鎭� - await doSendMessage(content) - event.preventDefault() // 闃叉榛樿鐨勬彁浜よ涓� - } - } -} - -/** 澶勭悊鏉ヨ嚜銆愬彂閫併�戞寜閽殑鍙戦�佹秷鎭� */ -const handleSendByButton = () => { - doSendMessage(prompt.value?.trim() as string) -} - -/** 澶勭悊 prompt 杈撳叆鍙樺寲 */ -const handlePromptInput = (event) => { - // 闈炶緭鍏ユ硶 杈撳叆璁剧疆涓� true - if (!isComposing.value) { - // 鍥炶溅 event data 鏄� null - if (event.data == null) { - return - } - isComposing.value = true - } - // 娓呯悊瀹氭椂鍣� - if (inputTimeout.value) { - clearTimeout(inputTimeout.value) - } - // 閲嶇疆瀹氭椂鍣� - inputTimeout.value = setTimeout(() => { - isComposing.value = false - }, 400) -} -// TODO @鑺嬭壙锛氭槸涓嶆槸鍙互閫氳繃 @keydown.enter銆丂keydown.shift.enter 鏉ュ疄鐜帮紝鍥炶溅鍙戦�併�乻hift+鍥炶溅鎹㈣锛涗富瑕佺湅鐪嬶紝鏄笉鏄彲浠ョ畝鍖� isComposing 鐩稿叧鐨勯�昏緫 -const onCompositionstart = () => { - isComposing.value = true -} -const onCompositionend = () => { - // console.log('杈撳叆缁撴潫...') - setTimeout(() => { - isComposing.value = false - }, 200) -} - -/** 鐪熸鎵ц銆愬彂閫併�戞秷鎭搷浣� */ -const doSendMessage = async (content: string) => { - // 鏍¢獙 - if (content.length < 1) { - message.error('鍙戦�佸け璐ワ紝鍘熷洜锛氬唴瀹逛负绌猴紒') - return - } - if (activeConversationId.value == null) { - message.error('杩樻病鍒涘缓瀵硅瘽锛屼笉鑳藉彂閫�!') - return - } - // 娓呯┖杈撳叆妗� - prompt.value = '' - // 鎵ц鍙戦�� - await doSendMessageStream({ - conversationId: activeConversationId.value, - content: content - } as ChatMessageVO) -} - -/** 鐪熸鎵ц銆愬彂閫併�戞秷鎭搷浣� */ -const doSendMessageStream = async (userMessage: ChatMessageVO) => { - // 鍒涘缓 AbortController 瀹炰緥锛屼互渚夸腑姝㈣姹� - conversationInAbortController.value = new AbortController() - // 鏍囪瀵硅瘽杩涜涓� - conversationInProgress.value = true - // 璁剧疆涓虹┖ - receiveMessageFullText.value = '' - - try { - // 1.1 鍏堟坊鍔犱袱涓亣鏁版嵁锛岀瓑 stream 杩斿洖鍐嶆浛鎹� - activeMessageList.value.push({ - id: -1, - conversationId: activeConversationId.value, - type: 'user', - content: userMessage.content, - createTime: new Date() - } as ChatMessageVO) - activeMessageList.value.push({ - id: -2, - conversationId: activeConversationId.value, - type: 'assistant', - content: '鎬濊�冧腑...', - createTime: new Date() - } as ChatMessageVO) - // 1.2 婊氬姩鍒版渶涓嬮潰 - await nextTick() - await scrollToBottom() // 搴曢儴 - // 1.3 寮�濮嬫粴鍔� - textRoll() - - // 2. 鍙戦�� event stream - let isFirstChunk = true // 鏄惁鏄涓�涓� chunk 娑堟伅娈� - await ChatMessageApi.sendChatMessageStream( - userMessage.conversationId, - userMessage.content, - conversationInAbortController.value, - enableContext.value, - async (res) => { - const { code, data, msg } = JSON.parse(res.data) - if (code !== 0) { - message.alert(`瀵硅瘽寮傚父! ${msg}`) - return - } - - // 濡傛灉鍐呭涓虹┖锛屽氨涓嶅鐞嗐�� - if (data.receive.content === '') { - return - } - // 棣栨杩斿洖闇�瑕佹坊鍔犱竴涓� message 鍒伴〉闈紝鍚庨潰鐨勯兘鏄洿鏂� - if (isFirstChunk) { - isFirstChunk = false - // 寮瑰嚭涓や釜鍋囨暟鎹� - activeMessageList.value.pop() - activeMessageList.value.pop() - // 鏇存柊杩斿洖鐨勬暟鎹� - activeMessageList.value.push(data.send) - activeMessageList.value.push(data.receive) - } - // debugger - receiveMessageFullText.value = receiveMessageFullText.value + data.receive.content - // 婊氬姩鍒版渶涓嬮潰 - await scrollToBottom() - }, - (error) => { - message.alert(`瀵硅瘽寮傚父! ${error}`) - stopStream() - }, - () => { - stopStream() - } - ) - } catch {} -} - -/** 鍋滄 stream 娴佸紡璋冪敤 */ -const stopStream = async () => { - // tip锛氬鏋� stream 杩涜涓殑 message锛屽氨闇�瑕佽皟鐢� controller 缁撴潫 - if (conversationInAbortController.value) { - conversationInAbortController.value.abort() - } - // 璁剧疆涓� false - conversationInProgress.value = false -} - -/** 缂栬緫 message锛氳缃负 prompt锛屽彲浠ュ啀娆$紪杈� */ -const handleMessageEdit = (message: ChatMessageVO) => { - prompt.value = message.content -} - -/** 鍒锋柊 message锛氬熀浜庢寚瀹氭秷鎭紝鍐嶆鍙戣捣瀵硅瘽 */ -const handleMessageRefresh = (message: ChatMessageVO) => { - doSendMessage(message.content) -} - -// ============== 銆愭秷鎭粴鍔ㄣ�戠浉鍏� ============= - -/** 婊氬姩鍒� message 搴曢儴 */ -const scrollToBottom = async (isIgnore?: boolean) => { - await nextTick() - if (messageRef.value) { - messageRef.value.scrollToBottom(isIgnore) - } -} - -/** 鑷彁婊氬姩鏁堟灉 */ -const textRoll = async () => { - let index = 0 - try { - // 鍙兘鎵ц涓�娆� - if (textRoleRunning.value) { - return - } - // 璁剧疆鐘舵�� - textRoleRunning.value = true - receiveMessageDisplayedText.value = '' - const task = async () => { - // 璋冩暣閫熷害 - const diff = - (receiveMessageFullText.value.length - receiveMessageDisplayedText.value.length) / 10 - if (diff > 5) { - textSpeed.value = 10 - } else if (diff > 2) { - textSpeed.value = 30 - } else if (diff > 1.5) { - textSpeed.value = 50 - } else { - textSpeed.value = 100 - } - // 瀵硅瘽缁撴潫锛屽氨鎸� 30 鐨勯�熷害 - if (!conversationInProgress.value) { - textSpeed.value = 10 - } - - if (index < receiveMessageFullText.value.length) { - receiveMessageDisplayedText.value += receiveMessageFullText.value[index] - index++ - - // 鏇存柊 message - const lastMessage = activeMessageList.value[activeMessageList.value.length - 1] - lastMessage.content = receiveMessageDisplayedText.value - // 婊氬姩鍒颁綇涓嬮潰 - await scrollToBottom() - // 閲嶆柊璁剧疆浠诲姟 - timer = setTimeout(task, textSpeed.value) - } else { - // 涓嶆槸瀵硅瘽涓彲浠ョ粨鏉� - if (!conversationInProgress.value) { - textRoleRunning.value = false - clearTimeout(timer) - } else { - // 閲嶆柊璁剧疆浠诲姟 - timer = setTimeout(task, textSpeed.value) - } - } - } - let timer = setTimeout(task, textSpeed.value) - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - // 濡傛灉鏈� conversationId 鍙傛暟锛屽垯榛樿閫変腑 - if (route.query.conversationId) { - const id = route.query.conversationId as unknown as number - activeConversationId.value = id - await getConversation(id) - } - - // 鑾峰彇鍒楄〃鏁版嵁 - activeMessageListLoading.value = true - await getMessageList() -}) -</script> - -<style lang="scss" scoped> -.ai-layout { - position: absolute; - flex: 1; - top: 0; - left: 0; - height: 100%; - width: 100%; -} - -.conversation-container { - position: relative; - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 10px 10px 0; - - .btn-new-conversation { - padding: 18px 0; - } - - .search-input { - margin-top: 20px; - } - - .conversation-list { - margin-top: 20px; - - .conversation { - display: flex; - flex-direction: row; - justify-content: space-between; - flex: 1; - padding: 0 5px; - margin-top: 10px; - cursor: pointer; - border-radius: 5px; - align-items: center; - line-height: 30px; - - &.active { - background-color: #e6e6e6; - - .button { - display: inline-block; - } - } - - .title-wrapper { - display: flex; - flex-direction: row; - align-items: center; - } - - .title { - padding: 5px 10px; - max-width: 220px; - font-size: 14px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .avatar { - width: 28px; - height: 28px; - display: flex; - flex-direction: row; - justify-items: center; - } - - // 瀵硅瘽缂栬緫銆佸垹闄� - .button-wrapper { - right: 2px; - display: flex; - flex-direction: row; - justify-items: center; - color: #606266; - - .el-icon { - margin-right: 5px; - } - } - } - } - - // 瑙掕壊浠撳簱銆佹竻绌烘湭璁剧疆瀵硅瘽 - .tool-box { - line-height: 35px; - display: flex; - justify-content: space-between; - align-items: center; - color: var(--el-text-color); - - > div { - display: flex; - align-items: center; - color: #606266; - padding: 0; - margin: 0; - cursor: pointer; - - > span { - margin-left: 5px; - } - } - } -} - -// 澶撮儴 -.detail-container { - background: #ffffff; - - .header { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - background: #fbfbfb; - box-shadow: 0 0 0 0 #dcdfe6; - - .title { - font-size: 18px; - font-weight: bold; - } - - .btns { - display: flex; - width: 300px; - flex-direction: row; - justify-content: flex-end; - //justify-content: space-between; - - .btn { - padding: 10px; - } - } - } -} - -// main 瀹瑰櫒 -.main-container { - margin: 0; - padding: 0; - position: relative; - height: 100%; - width: 100%; - - .message-container { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - overflow-y: hidden; - padding: 0; - margin: 0; - } -} - -// 搴曢儴 -.footer-container { - display: flex; - flex-direction: column; - height: auto; - margin: 0; - padding: 0; - - .prompt-from { - display: flex; - flex-direction: column; - height: auto; - border: 1px solid #e3e3e3; - border-radius: 10px; - margin: 10px 20px 20px 20px; - padding: 9px 10px; - } - - .prompt-input { - height: 80px; - //box-shadow: none; - border: none; - box-sizing: border-box; - resize: none; - padding: 0 2px; - overflow: auto; - } - - .prompt-input:focus { - outline: none; - } - - .prompt-btns { - display: flex; - justify-content: space-between; - padding-bottom: 0; - padding-top: 5px; - } -} -</style> diff --git a/src/views/ai/chat/manager/ChatConversationList.vue b/src/views/ai/chat/manager/ChatConversationList.vue deleted file mode 100644 index 23933f0..0000000 --- a/src/views/ai/chat/manager/ChatConversationList.vue +++ /dev/null @@ -1,163 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-select - v-model="queryParams.userId" - clearable - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鑱婂ぉ缂栧彿" prop="title"> - <el-input - v-model="queryParams.title" - placeholder="璇疯緭鍏ヨ亰澶╃紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="瀵硅瘽缂栧彿" align="center" prop="id" width="180" fixed="left" /> - <el-table-column label="瀵硅瘽鏍囬" align="center" prop="title" width="180" fixed="left" /> - <el-table-column label="鐢ㄦ埛" align="center" prop="userId" width="180"> - <template #default="scope"> - <span>{{ userList.find((item) => item.id === scope.row.userId)?.nickname }}</span> - </template> - </el-table-column> - <el-table-column label="瑙掕壊" align="center" prop="roleName" width="180" /> - <el-table-column label="妯″瀷鏍囪瘑" align="center" prop="model" width="180" /> - <el-table-column label="娑堟伅鏁�" align="center" prop="messageCount" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="娓╁害鍙傛暟" align="center" prop="temperature" /> - <el-table-column label="鍥炲 Token 鏁�" align="center" prop="maxTokens" width="120" /> - <el-table-column label="涓婁笅鏂囨暟閲�" align="center" prop="maxContexts" width="120" /> - <el-table-column label="鎿嶄綔" align="center" width="180" fixed="right"> - <template #default="scope"> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:chat-conversation:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation' -import * as UserApi from '@/api/system/user' - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ChatConversationVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: undefined, - title: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ChatConversationApi.getChatConversationPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ChatConversationApi.deleteChatConversationByAdmin(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/ai/chat/manager/ChatMessageList.vue b/src/views/ai/chat/manager/ChatMessageList.vue deleted file mode 100644 index 0d84184..0000000 --- a/src/views/ai/chat/manager/ChatMessageList.vue +++ /dev/null @@ -1,175 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="瀵硅瘽缂栧彿" prop="conversationId"> - <el-input - v-model="queryParams.conversationId" - placeholder="璇疯緭鍏ュ璇濈紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-select - v-model="queryParams.userId" - clearable - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="娑堟伅缂栧彿" align="center" prop="id" width="180" fixed="left" /> - <el-table-column - label="瀵硅瘽缂栧彿" - align="center" - prop="conversationId" - width="180" - fixed="left" - /> - <el-table-column label="鐢ㄦ埛" align="center" prop="userId" width="180"> - <template #default="scope"> - <span>{{ userList.find((item) => item.id === scope.row.userId)?.nickname }}</span> - </template> - </el-table-column> - <el-table-column label="瑙掕壊" align="center" prop="roleName" width="180" /> - <el-table-column label="娑堟伅绫诲瀷" align="center" prop="type" width="100" /> - <el-table-column label="妯″瀷鏍囪瘑" align="center" prop="model" width="180" /> - <el-table-column label="娑堟伅鍐呭" align="center" prop="content" width="300" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鍥炲娑堟伅缂栧彿" align="center" prop="replyId" width="180" /> - <el-table-column label="鎼哄甫涓婁笅鏂�" align="center" prop="useContext" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.useContext" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right"> - <template #default="scope"> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:chat-message:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message' -import * as UserApi from '@/api/system/user' -import { DICT_TYPE } from '@/utils/dict' - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ChatMessageVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - conversationId: undefined, - userId: undefined, - content: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ChatMessageApi.getChatMessagePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ChatMessageApi.deleteChatMessageByAdmin(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/ai/chat/manager/index.vue b/src/views/ai/chat/manager/index.vue deleted file mode 100644 index ca2d092..0000000 --- a/src/views/ai/chat/manager/index.vue +++ /dev/null @@ -1,20 +0,0 @@ -<template> - <ContentWrap> - <el-tabs> - <el-tab-pane label="瀵硅瘽鍒楄〃"> - <ChatConversationList /> - </el-tab-pane> - <el-tab-pane label="娑堟伅鍒楄〃"> - <ChatMessageList /> - </el-tab-pane> - </el-tabs> - </ContentWrap> -</template> - -<script setup lang="ts"> -import ChatConversationList from './ChatConversationList.vue' -import ChatMessageList from './ChatMessageList.vue' - -/** AI 鑱婂ぉ瀵硅瘽 鍒楄〃 */ -defineOptions({ name: 'AiChatManager' }) -</script> diff --git a/src/views/ai/image/index/components/ImageCard.vue b/src/views/ai/image/index/components/ImageCard.vue deleted file mode 100644 index 4ba78ca..0000000 --- a/src/views/ai/image/index/components/ImageCard.vue +++ /dev/null @@ -1,162 +0,0 @@ -<template> - <el-card body-class="" class="image-card"> - <div class="image-operation"> - <div> - <el-button type="primary" text bg v-if="detail?.status === AiImageStatusEnum.IN_PROGRESS"> - 鐢熸垚涓� - </el-button> - <el-button text bg v-else-if="detail?.status === AiImageStatusEnum.SUCCESS"> - 宸插畬鎴� - </el-button> - <el-button type="danger" text bg v-else-if="detail?.status === AiImageStatusEnum.FAIL"> - 寮傚父 - </el-button> - </div> - <!-- 鎿嶄綔鍖� --> - <div> - <el-button - class="btn" - text - :icon="Download" - @click="handleButtonClick('download', detail)" - /> - <el-button - class="btn" - text - :icon="RefreshRight" - @click="handleButtonClick('regeneration', detail)" - /> - <el-button class="btn" text :icon="Delete" @click="handleButtonClick('delete', detail)" /> - <el-button class="btn" text :icon="More" @click="handleButtonClick('more', detail)" /> - </div> - </div> - <div class="image-wrapper" ref="cardImageRef"> - <el-image - class="image" - :src="detail?.picUrl" - :preview-src-list="[detail.picUrl]" - preview-teleported - /> - <div v-if="detail?.status === AiImageStatusEnum.FAIL"> - {{ detail?.errorMessage }} - </div> - </div> - <!-- Midjourney 涓撳睘鎿嶄綔 --> - <div class="image-mj-btns"> - <el-button - size="small" - v-for="button in detail?.buttons" - :key="button" - class="min-w-40px ml-0 mr-10px mt-5px" - @click="handleMidjourneyBtnClick(button)" - > - {{ button.label }}{{ button.emoji }} - </el-button> - </div> - </el-card> -</template> -<script setup lang="ts"> -import { Delete, Download, More, RefreshRight } from '@element-plus/icons-vue' -import { ImageVO, ImageMidjourneyButtonsVO } from '@/api/ai/image' -import { PropType } from 'vue' -import { ElLoading, LoadingOptionsResolved } from 'element-plus' -import { AiImageStatusEnum } from '@/views/ai/utils/constants' - -const message = useMessage() // 娑堟伅 - -const props = defineProps({ - detail: { - type: Object as PropType<ImageVO>, - require: true - } -}) - -const cardImageRef = ref<any>() // 鍗$墖 image ref -const cardImageLoadingInstance = ref<any>() // 鍗$墖 image ref - -/** 澶勭悊鐐瑰嚮浜嬩欢 */ -const handleButtonClick = async (type, detail: ImageVO) => { - emits('onBtnClick', type, detail) -} - -/** 澶勭悊 Midjourney 鎸夐挳鐐瑰嚮浜嬩欢 */ -const handleMidjourneyBtnClick = async (button: ImageMidjourneyButtonsVO) => { - // 纭绐椾綋 - await message.confirm(`纭鎿嶄綔 "${button.label} ${button.emoji}" ?`) - emits('onMjBtnClick', button, props.detail) -} - -const emits = defineEmits(['onBtnClick', 'onMjBtnClick']) // emits - -/** 鐩戝惉璇︽儏 */ -const { detail } = toRefs(props) -watch(detail, async (newVal, oldVal) => { - await handleLoading(newVal.status as string) -}) - -/** 澶勭悊鍔犺浇鐘舵�� */ -const handleLoading = async (status: number) => { - // 鎯呭喌涓�锛氬鏋滄槸鐢熸垚涓紝鍒欒缃姞杞戒腑鐨� loading - if (status === AiImageStatusEnum.IN_PROGRESS) { - cardImageLoadingInstance.value = ElLoading.service({ - target: cardImageRef.value, - text: '鐢熸垚涓�...' - } as LoadingOptionsResolved) - // 鎯呭喌浜岋細濡傛灉宸茬粡鐢熸垚缁撴潫锛屽垯绉婚櫎 loading - } else { - if (cardImageLoadingInstance.value) { - cardImageLoadingInstance.value.close() - cardImageLoadingInstance.value = null - } - } -} - -/** 鍒濆鍖� */ -onMounted(async () => { - await handleLoading(props.detail.status as string) -}) -</script> - -<style scoped lang="scss"> -.image-card { - width: 320px; - height: auto; - border-radius: 10px; - position: relative; - display: flex; - flex-direction: column; - - .image-operation { - display: flex; - flex-direction: row; - justify-content: space-between; - - .btn { - //border: 1px solid red; - padding: 10px; - margin: 0; - } - } - - .image-wrapper { - overflow: hidden; - margin-top: 20px; - height: 280px; - flex: 1; - - .image { - width: 100%; - border-radius: 10px; - } - } - - .image-mj-btns { - margin-top: 5px; - width: 100%; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: flex-start; - } -} -</style> diff --git a/src/views/ai/image/index/components/ImageDetail.vue b/src/views/ai/image/index/components/ImageDetail.vue deleted file mode 100644 index ad15aa8..0000000 --- a/src/views/ai/image/index/components/ImageDetail.vue +++ /dev/null @@ -1,224 +0,0 @@ -<template> - <el-drawer - v-model="showDrawer" - title="鍥剧墖璇︾粏" - @close="handleDrawerClose" - custom-class="drawer-class" - > - <!-- 鍥剧墖 --> - <div class="item"> - <div class="body"> - <el-image - class="image" - :src="detail?.picUrl" - :preview-src-list="[detail.picUrl]" - preview-teleported - /> - </div> - </div> - <!-- 鏃堕棿 --> - <div class="item"> - <div class="tip">鏃堕棿</div> - <div class="body"> - <div>鎻愪氦鏃堕棿锛歿{ formatTime(detail.createTime, 'yyyy-MM-dd HH:mm:ss') }}</div> - <div>鐢熸垚鏃堕棿锛歿{ formatTime(detail.finishTime, 'yyyy-MM-dd HH:mm:ss') }}</div> - </div> - </div> - <!-- 妯″瀷 --> - <div class="item"> - <div class="tip">妯″瀷</div> - <div class="body"> {{ detail.model }}({{ detail.height }}x{{ detail.width }}) </div> - </div> - <!-- 鎻愮ず璇� --> - <div class="item"> - <div class="tip">鎻愮ず璇�</div> - <div class="body"> - {{ detail.prompt }} - </div> - </div> - <!-- 鍦板潃 --> - <div class="item"> - <div class="tip">鍥剧墖鍦板潃</div> - <div class="body"> - {{ detail.picUrl }} - </div> - </div> - <!-- StableDiffusion 涓撳睘鍖哄煙 --> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.sampler" - > - <div class="tip">閲囨牱鏂规硶</div> - <div class="body"> - {{ - StableDiffusionSamplers.find( - (item: ImageModelVO) => item.key === detail?.options?.sampler - )?.name - }} - </div> - </div> - <div - class="item" - v-if=" - detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.clipGuidancePreset - " - > - <div class="tip">CLIP</div> - <div class="body"> - {{ - StableDiffusionClipGuidancePresets.find( - (item: ImageModelVO) => item.key === detail?.options?.clipGuidancePreset - )?.name - }} - </div> - </div> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.stylePreset" - > - <div class="tip">椋庢牸</div> - <div class="body"> - {{ - StableDiffusionStylePresets.find( - (item: ImageModelVO) => item.key === detail?.options?.stylePreset - )?.name - }} - </div> - </div> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.steps" - > - <div class="tip">杩唬姝ユ暟</div> - <div class="body"> - {{ detail?.options?.steps }} - </div> - </div> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.scale" - > - <div class="tip">寮曞绯绘暟</div> - <div class="body"> - {{ detail?.options?.scale }} - </div> - </div> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.STABLE_DIFFUSION && detail?.options?.seed" - > - <div class="tip">闅忔満鍥犲瓙</div> - <div class="body"> - {{ detail?.options?.seed }} - </div> - </div> - <!-- Dall3 涓撳睘鍖哄煙 --> - <div class="item" v-if="detail.platform === AiPlatformEnum.OPENAI && detail?.options?.style"> - <div class="tip">椋庢牸閫夋嫨</div> - <div class="body"> - {{ Dall3StyleList.find((item: ImageModelVO) => item.key === detail?.options?.style)?.name }} - </div> - </div> - <!-- Midjourney 涓撳睘鍖哄煙 --> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.MIDJOURNEY && detail?.options?.version" - > - <div class="tip">妯″瀷鐗堟湰</div> - <div class="body"> - {{ detail?.options?.version }} - </div> - </div> - <div - class="item" - v-if="detail.platform === AiPlatformEnum.MIDJOURNEY && detail?.options?.referImageUrl" - > - <div class="tip">鍙傝�冨浘</div> - <div class="body"> - <el-image :src="detail.options.referImageUrl" /> - </div> - </div> - </el-drawer> -</template> - -<script setup lang="ts"> -import { ImageApi, ImageVO } from '@/api/ai/image' -import { - AiPlatformEnum, - Dall3StyleList, - ImageModelVO, - StableDiffusionClipGuidancePresets, - StableDiffusionSamplers, - StableDiffusionStylePresets -} from '@/views/ai/utils/constants' -import { formatTime } from '@/utils' - -const showDrawer = ref<boolean>(false) // 鏄惁鏄剧ず -const detail = ref<ImageVO>({} as ImageVO) // 鍥剧墖璇︾粏淇℃伅 - -const props = defineProps({ - show: { - type: Boolean, - require: true, - default: false - }, - id: { - type: Number, - required: true - } -}) - -/** 鍏抽棴鎶藉眽 */ -const handleDrawerClose = async () => { - emits('handleDrawerClose') -} - -/** 鐩戝惉 drawer 鏄惁鎵撳紑 */ -const { show } = toRefs(props) -watch(show, async (newValue, oldValue) => { - showDrawer.value = newValue as boolean -}) - -/** 鑾峰彇鍥剧墖璇︽儏 */ -const getImageDetail = async (id: number) => { - detail.value = await ImageApi.getImageMy(id) -} - -/** 鐩戝惉 id 鍙樺寲锛屽姞杞芥渶鏂板浘鐗囪鎯� */ -const { id } = toRefs(props) -watch(id, async (newVal, oldVal) => { - if (newVal) { - await getImageDetail(newVal) - } -}) - -const emits = defineEmits(['handleDrawerClose']) -</script> -<style scoped lang="scss"> -.item { - margin-bottom: 20px; - width: 100%; - overflow: hidden; - word-wrap: break-word; - - .header { - display: flex; - flex-direction: row; - justify-content: space-between; - } - - .tip { - font-weight: bold; - font-size: 16px; - } - - .body { - margin-top: 10px; - color: #616161; - - .taskImage { - border-radius: 10px; - } - } -} -</style> diff --git a/src/views/ai/image/index/components/ImageList.vue b/src/views/ai/image/index/components/ImageList.vue deleted file mode 100644 index cdd1e20..0000000 --- a/src/views/ai/image/index/components/ImageList.vue +++ /dev/null @@ -1,233 +0,0 @@ -<template> - <el-card class="dr-task" body-class="task-card" shadow="never"> - <template #header>缁樼敾浠诲姟</template> - <!-- 鍥剧墖鍒楄〃 --> - <div class="task-image-list" ref="imageListRef"> - <ImageCard - v-for="image in imageList" - :key="image.id" - :detail="image" - @on-btn-click="handleImageButtonClick" - @on-mj-btn-click="handleImageMidjourneyButtonClick" - /> - </div> - <div class="task-image-pagination"> - <Pagination - :total="pageTotal" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getImageList" - /> - </div> - </el-card> - - <!-- 鍥剧墖璇︽儏 --> - <ImageDetail - :show="isShowImageDetail" - :id="showImageDetailId" - @handle-drawer-close="handleDetailClose" - /> -</template> -<script setup lang="ts"> -import { - ImageApi, - ImageVO, - ImageMidjourneyActionVO, - ImageMidjourneyButtonsVO -} from '@/api/ai/image' -import ImageDetail from './ImageDetail.vue' -import ImageCard from './ImageCard.vue' -import { ElLoading, LoadingOptionsResolved } from 'element-plus' -import { AiImageStatusEnum } from '@/views/ai/utils/constants' -import download from '@/utils/download' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 鍥剧墖鍒嗛〉鐩稿叧鐨勫弬鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10 -}) -const pageTotal = ref<number>(0) // page size -const imageList = ref<ImageVO[]>([]) // image 鍒楄〃 -const imageListLoadingInstance = ref<any>() // image 鍒楄〃鏄惁姝e湪鍔犺浇涓� -const imageListRef = ref<any>() // ref -// 鍥剧墖杞鐩稿叧鐨勫弬鏁帮紙姝e湪鐢熸垚涓殑锛� -const inProgressImageMap = ref<{}>({}) // 鐩戝惉鐨� image 鏄犲皠锛屼竴鑸槸鐢熸垚涓紙闇�瑕佽疆璇級锛宬ey 涓� image 缂栧彿锛寁alue 涓� image -const inProgressTimer = ref<any>() // 鐢熸垚涓殑 image 瀹氭椂鍣紝杞鐢熸垚杩涘睍 -// 鍥剧墖璇︽儏鐩稿叧鐨勫弬鏁� -const isShowImageDetail = ref<boolean>(false) // 鍥剧墖璇︽儏鏄惁灞曠ず -const showImageDetailId = ref<number>(0) // 鍥剧墖璇︽儏鐨勫浘鐗囩紪鍙� - -/** 鏌ョ湅鍥剧墖鐨勮鎯� */ -const handleDetailOpen = async () => { - isShowImageDetail.value = true -} - -/** 鍏抽棴鍥剧墖鐨勮鎯� */ -const handleDetailClose = async () => { - isShowImageDetail.value = false -} - -/** 鑾峰緱 image 鍥剧墖鍒楄〃 */ -const getImageList = async () => { - try { - // 1. 鍔犺浇鍥剧墖鍒楄〃 - imageListLoadingInstance.value = ElLoading.service({ - target: imageListRef.value, - text: '鍔犺浇涓�...' - } as LoadingOptionsResolved) - const { list, total } = await ImageApi.getImagePageMy(queryParams) - imageList.value = list - pageTotal.value = total - - // 2. 璁$畻闇�瑕佽疆璇㈢殑鍥剧墖 - const newWatImages = {} - imageList.value.forEach((item) => { - if (item.status === AiImageStatusEnum.IN_PROGRESS) { - newWatImages[item.id] = item - } - }) - inProgressImageMap.value = newWatImages - } finally { - // 鍏抽棴姝e湪鈥滃姞杞戒腑鈥濈殑 Loading - if (imageListLoadingInstance.value) { - imageListLoadingInstance.value.close() - imageListLoadingInstance.value = null - } - } -} - -/** 杞鐢熸垚涓殑 image 鍒楄〃 */ -const refreshWatchImages = async () => { - const imageIds = Object.keys(inProgressImageMap.value).map(Number) - if (imageIds.length == 0) { - return - } - const list = (await ImageApi.getImageListMyByIds(imageIds)) as ImageVO[] - const newWatchImages = {} - list.forEach((image) => { - if (image.status === AiImageStatusEnum.IN_PROGRESS) { - newWatchImages[image.id] = image - } else { - const index = imageList.value.findIndex((oldImage) => image.id === oldImage.id) - if (index >= 0) { - // 鏇存柊 imageList - imageList.value[index] = image - } - } - }) - inProgressImageMap.value = newWatchImages -} - -/** 鍥剧墖鐨勭偣鍑讳簨浠� */ -const handleImageButtonClick = async (type: string, imageDetail: ImageVO) => { - // 璇︽儏 - if (type === 'more') { - showImageDetailId.value = imageDetail.id - await handleDetailOpen() - return - } - // 鍒犻櫎 - if (type === 'delete') { - await message.confirm(`鏄惁鍒犻櫎鐓х墖?`) - await ImageApi.deleteImageMy(imageDetail.id) - await getImageList() - message.success('鍒犻櫎鎴愬姛!') - return - } - // 涓嬭浇 - if (type === 'download') { - await download.image(imageDetail.picUrl) - return - } - // 閲嶆柊鐢熸垚 - if (type === 'regeneration') { - await emits('onRegeneration', imageDetail) - return - } -} - -/** 澶勭悊 Midjourney 鎸夐挳鐐瑰嚮浜嬩欢 */ -const handleImageMidjourneyButtonClick = async ( - button: ImageMidjourneyButtonsVO, - imageDetail: ImageVO -) => { - // 1. 鏋勫缓 params 鍙傛暟 - const data = { - id: imageDetail.id, - customId: button.customId - } as ImageMidjourneyActionVO - // 2. 鍙戦�� action - await ImageApi.midjourneyAction(data) - // 3. 鍒锋柊鍒楄〃 - await getImageList() -} - -defineExpose({ getImageList }) // 鏆撮湶缁勪欢鏂规硶 - -const emits = defineEmits(['onRegeneration']) - -/** 缁勪欢鎸傚湪鐨勬椂鍊� */ -onMounted(async () => { - // 鑾峰彇 image 鍒楄〃 - await getImageList() - // 鑷姩鍒锋柊 image 鍒楄〃 - inProgressTimer.value = setInterval(async () => { - await refreshWatchImages() - }, 1000 * 3) -}) - -/** 缁勪欢鍙栨秷鎸傚湪鐨勬椂鍊� */ -onUnmounted(async () => { - if (inProgressTimer.value) { - clearInterval(inProgressTimer.value) - } -}) -</script> -<style lang="scss"> -.dr-task { - width: 100%; - height: 100%; -} -.task-card { - margin: 0; - padding: 0; - height: 100%; - position: relative; -} - -.task-image-list { - position: relative; - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-content: flex-start; - height: 100%; - overflow: auto; - padding: 20px 20px 140px; - box-sizing: border-box; /* 纭繚鍐呰竟璺濅笉浼氬鍔犻珮搴� */ - - > div { - margin-right: 20px; - margin-bottom: 20px; - } - > div:last-of-type { - //margin-bottom: 100px; - } -} - -.task-image-pagination { - position: absolute; - bottom: 60px; - height: 50px; - line-height: 90px; - width: 100%; - z-index: 999; - background-color: #ffffff; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; -} -</style> diff --git a/src/views/ai/image/index/components/dall3/index.vue b/src/views/ai/image/index/components/dall3/index.vue deleted file mode 100644 index 5c891ab..0000000 --- a/src/views/ai/image/index/components/dall3/index.vue +++ /dev/null @@ -1,320 +0,0 @@ -<!-- dall3 --> -<template> - <div class="prompt"> - <el-text tag="b">鐢婚潰鎻忚堪</el-text> - <el-text tag="p">寤鸿浣跨敤鈥滃舰瀹硅瘝+鍔ㄨ瘝+椋庢牸鈥濈殑鏍煎紡锛屼娇鐢ㄢ�滐紝鈥濋殧寮�</el-text> - <el-input - v-model="prompt" - maxlength="1024" - rows="5" - class="w-100% mt-15px" - input-style="border-radius: 7px;" - placeholder="渚嬪锛氱璇濋噷鐨勫皬灞嬪簲璇ユ槸浠�涔堟牱瀛愶紵" - show-word-limit - type="textarea" - /> - </div> - <div class="hot-words"> - <div> - <el-text tag="b">闅忔満鐑瘝</el-text> - </div> - <el-space wrap class="word-list"> - <el-button - round - class="btn" - :type="selectHotWord === hotWord ? 'primary' : 'default'" - v-for="hotWord in ImageHotWords" - :key="hotWord" - @click="handleHotWordClick(hotWord)" - > - {{ hotWord }} - </el-button> - </el-space> - </div> - <div class="model"> - <div> - <el-text tag="b">妯″瀷閫夋嫨</el-text> - </div> - <el-space wrap class="model-list"> - <div - :class="selectModel === model.key ? 'modal-item selectModel' : 'modal-item'" - v-for="model in Dall3Models" - :key="model.key" - > - <el-image :src="model.image" fit="contain" @click="handleModelClick(model)" /> - <div class="model-font">{{ model.name }}</div> - </div> - </el-space> - </div> - <div class="image-style"> - <div> - <el-text tag="b">椋庢牸閫夋嫨</el-text> - </div> - <el-space wrap class="image-style-list"> - <div - :class="style === imageStyle.key ? 'image-style-item selectImageStyle' : 'image-style-item'" - v-for="imageStyle in Dall3StyleList" - :key="imageStyle.key" - > - <el-image :src="imageStyle.image" fit="contain" @click="handleStyleClick(imageStyle)" /> - <div class="style-font">{{ imageStyle.name }}</div> - </div> - </el-space> - </div> - <div class="image-size"> - <div> - <el-text tag="b">鐢婚潰姣斾緥</el-text> - </div> - <el-space wrap class="size-list"> - <div - class="size-item" - v-for="imageSize in Dall3SizeList" - :key="imageSize.key" - @click="handleSizeClick(imageSize)" - > - <div - :class="selectSize === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'" - > - <div :style="imageSize.style"></div> - </div> - <div class="size-font">{{ imageSize.name }}</div> - </div> - </el-space> - </div> - <div class="btns"> - <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage"> - {{ drawIn ? '鐢熸垚涓�' : '鐢熸垚鍐呭' }} - </el-button> - </div> -</template> -<script setup lang="ts"> -import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image' -import { - Dall3Models, - Dall3StyleList, - ImageHotWords, - Dall3SizeList, - ImageModelVO, - AiPlatformEnum -} from '@/views/ai/utils/constants' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 瀹氫箟灞炴�� -const prompt = ref<string>('') // 鎻愮ず璇� -const drawIn = ref<boolean>(false) // 鐢熸垚涓� -const selectHotWord = ref<string>('') // 閫変腑鐨勭儹璇� -const selectModel = ref<string>('dall-e-3') // 妯″瀷 -const selectSize = ref<string>('1024x1024') // 閫変腑 size -const style = ref<string>('vivid') // style 鏍峰紡 - -const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 瀹氫箟 emits - -/** 閫夋嫨鐑瘝 */ -const handleHotWordClick = async (hotWord: string) => { - // 鎯呭喌涓�锛氬彇娑堥�変腑 - if (selectHotWord.value == hotWord) { - selectHotWord.value = '' - return - } - - // 鎯呭喌浜岋細閫変腑 - selectHotWord.value = hotWord - prompt.value = hotWord -} - -/** 閫夋嫨 model 妯″瀷 */ -const handleModelClick = async (model: ImageModelVO) => { - selectModel.value = model.key -} - -/** 閫夋嫨 style 鏍峰紡 */ -const handleStyleClick = async (imageStyle: ImageModelVO) => { - style.value = imageStyle.key -} - -/** 閫夋嫨 size 澶у皬 */ -const handleSizeClick = async (imageSize: ImageSizeVO) => { - selectSize.value = imageSize.key -} - -/** 鍥剧墖鐢熶骇 */ -const handleGenerateImage = async () => { - // 浜屾纭 - await message.confirm(`纭鐢熸垚鍐呭?`) - try { - // 鍔犺浇涓� - drawIn.value = true - // 鍥炶皟 - emits('onDrawStart', AiPlatformEnum.OPENAI) - const imageSize = Dall3SizeList.find((item) => item.key === selectSize.value) as ImageSizeVO - const form = { - platform: AiPlatformEnum.OPENAI, - prompt: prompt.value, // 鎻愮ず璇� - model: selectModel.value, // 妯″瀷 - width: imageSize.width, // size 涓嶈兘涓虹┖ - height: imageSize.height, // size 涓嶈兘涓虹┖ - options: { - style: style.value // 鍥惧儚鐢熸垚鐨勯鏍� - } - } as ImageDrawReqVO - // 鍙戦�佽姹� - await ImageApi.drawImage(form) - } finally { - // 鍥炶皟 - emits('onDrawComplete', AiPlatformEnum.OPENAI) - // 鍔犺浇缁撴潫 - drawIn.value = false - } -} - -/** 濉厖鍊� */ -const settingValues = async (detail: ImageVO) => { - prompt.value = detail.prompt - selectModel.value = detail.model - style.value = detail.options?.style - const imageSize = Dall3SizeList.find( - (item) => item.key === `${detail.width}x${detail.height}` - ) as ImageSizeVO - await handleSizeClick(imageSize) -} - -/** 鏆撮湶缁勪欢鏂规硶 */ -defineExpose({ settingValues }) -</script> -<style scoped lang="scss"> -// 鎻愮ず璇� -.prompt { -} - -// 鐑瘝 -.hot-words { - display: flex; - flex-direction: column; - margin-top: 30px; - - .word-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: start; - margin-top: 15px; - - .btn { - margin: 0; - } - } -} - -// 妯″瀷 -.model { - margin-top: 30px; - - .model-list { - margin-top: 15px; - - .modal-item { - width: 110px; - //outline: 1px solid blue; - overflow: hidden; - display: flex; - flex-direction: column; - align-items: center; - border: 3px solid transparent; - cursor: pointer; - - .model-font { - font-size: 14px; - color: #3e3e3e; - font-weight: bold; - } - } - - .selectModel { - border: 3px solid #1293ff; - border-radius: 5px; - } - } -} - -// 鏍峰紡 style -.image-style { - margin-top: 30px; - - .image-style-list { - margin-top: 15px; - - .image-style-item { - width: 110px; - //outline: 1px solid blue; - overflow: hidden; - display: flex; - flex-direction: column; - align-items: center; - border: 3px solid transparent; - cursor: pointer; - - .style-font { - font-size: 14px; - color: #3e3e3e; - font-weight: bold; - } - } - - .selectImageStyle { - border: 3px solid #1293ff; - border-radius: 5px; - } - } -} - -// 灏哄 -.image-size { - width: 100%; - margin-top: 30px; - - .size-list { - display: flex; - flex-direction: row; - justify-content: space-between; - width: 100%; - margin-top: 20px; - - .size-item { - display: flex; - flex-direction: column; - align-items: center; - cursor: pointer; - - .size-wrapper { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - border-radius: 7px; - padding: 4px; - width: 50px; - height: 50px; - background-color: #fff; - border: 1px solid #fff; - } - - .size-font { - font-size: 14px; - color: #3e3e3e; - font-weight: bold; - } - } - } - - .selectImageSize { - border: 1px solid #1293ff !important; - } -} - -.btns { - display: flex; - justify-content: center; - margin-top: 50px; -} -</style> diff --git a/src/views/ai/image/index/components/midjourney/index.vue b/src/views/ai/image/index/components/midjourney/index.vue deleted file mode 100644 index 1d7fda1..0000000 --- a/src/views/ai/image/index/components/midjourney/index.vue +++ /dev/null @@ -1,326 +0,0 @@ -<!-- dall3 --> -<template> - <div class="prompt"> - <el-text tag="b">鐢婚潰鎻忚堪</el-text> - <el-text tag="p">寤鸿浣跨敤鈥滃舰瀹硅瘝+鍔ㄨ瘝+椋庢牸鈥濈殑鏍煎紡锛屼娇鐢ㄢ�滐紝鈥濋殧寮�.</el-text> - <el-input - v-model="prompt" - maxlength="1024" - rows="5" - class="w-100% mt-15px" - input-style="border-radius: 7px;" - placeholder="渚嬪锛氱璇濋噷鐨勫皬灞嬪簲璇ユ槸浠�涔堟牱瀛愶紵" - show-word-limit - type="textarea" - /> - </div> - <div class="hot-words"> - <div> - <el-text tag="b">闅忔満鐑瘝</el-text> - </div> - <el-space wrap class="word-list"> - <el-button - round - class="btn" - :type="selectHotWord === hotWord ? 'primary' : 'default'" - v-for="hotWord in ImageHotWords" - :key="hotWord" - @click="handleHotWordClick(hotWord)" - > - {{ hotWord }} - </el-button> - </el-space> - </div> - <div class="image-size"> - <div> - <el-text tag="b">灏哄</el-text> - </div> - <el-space wrap class="size-list"> - <div - class="size-item" - v-for="imageSize in MidjourneySizeList" - :key="imageSize.key" - @click="handleSizeClick(imageSize)" - > - <div - :class="selectSize === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'" - > - <div :style="imageSize.style"></div> - </div> - <div class="size-font">{{ imageSize.key }}</div> - </div> - </el-space> - </div> - <div class="model"> - <div> - <el-text tag="b">妯″瀷</el-text> - </div> - <el-space wrap class="model-list"> - <div - :class="selectModel === model.key ? 'modal-item selectModel' : 'modal-item'" - v-for="model in MidjourneyModels" - :key="model.key" - > - <el-image :src="model.image" fit="contain" @click="handleModelClick(model)" /> - <div class="model-font">{{ model.name }}</div> - </div> - </el-space> - </div> - <div class="version"> - <div> - <el-text tag="b">鐗堟湰</el-text> - </div> - <el-space wrap class="version-list"> - <el-select - v-model="selectVersion" - class="version-select !w-350px" - clearable - placeholder="璇烽�夋嫨鐗堟湰" - > - <el-option - v-for="item in versionList" - :key="item.value" - :label="item.label" - :value="item.value" - /> - </el-select> - </el-space> - </div> - <div class="model"> - <div> - <el-text tag="b">鍙傝�冨浘</el-text> - </div> - <el-space wrap class="model-list"> - <UploadImg v-model="referImageUrl" height="120px" width="120px" /> - </el-space> - </div> - <div class="btns"> - <el-button type="primary" size="large" round @click="handleGenerateImage"> - {{ drawIn ? '鐢熸垚涓�' : '鐢熸垚鍐呭' }} - </el-button> - </div> -</template> -<script setup lang="ts"> -import { ImageApi, ImageMidjourneyImagineReqVO, ImageVO } from '@/api/ai/image' -import { - AiPlatformEnum, - ImageHotWords, - ImageSizeVO, - ImageModelVO, - MidjourneyModels, - MidjourneySizeList, - MidjourneyVersions, - NijiVersionList -} from '@/views/ai/utils/constants' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 瀹氫箟灞炴�� -const drawIn = ref<boolean>(false) // 鐢熸垚涓� -const selectHotWord = ref<string>('') // 閫変腑鐨勭儹璇� -// 琛ㄥ崟 -const prompt = ref<string>('') // 鎻愮ず璇� -const referImageUrl = ref<any>() // 鍙傝�冨浘 -const selectModel = ref<string>('midjourney') // 閫変腑鐨勬ā鍨� -const selectSize = ref<string>('1:1') // 閫変腑 size -const selectVersion = ref<any>('6.0') // 閫変腑鐨� version -const versionList = ref<any>(MidjourneyVersions) // version 鍒楄〃 -const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 瀹氫箟 emits - -/** 閫夋嫨鐑瘝 */ -const handleHotWordClick = async (hotWord: string) => { - // 鎯呭喌涓�锛氬彇娑堥�変腑 - if (selectHotWord.value == hotWord) { - selectHotWord.value = '' - return - } - - // 鎯呭喌浜岋細閫変腑 - selectHotWord.value = hotWord // 閫変腑 - prompt.value = hotWord // 璁剧疆鎻愮ず娆� -} - -/** 鐐瑰嚮 size 灏哄 */ -const handleSizeClick = async (imageSize: ImageSizeVO) => { - selectSize.value = imageSize.key -} - -/** 鐐瑰嚮 model 妯″瀷 */ -const handleModelClick = async (model: ImageModelVO) => { - selectModel.value = model.key - if (model.key === 'niji') { - versionList.value = NijiVersionList // 榛樿閫夋嫨 niji - } else { - versionList.value = MidjourneyVersions // 榛樿閫夋嫨 midjourney - } - selectVersion.value = versionList.value[0].value -} - -/** 鍥剧墖鐢熸垚 */ -const handleGenerateImage = async () => { - // 浜屾纭 - await message.confirm(`纭鐢熸垚鍐呭?`) - try { - // 鍔犺浇涓� - drawIn.value = true - // 鍥炶皟 - emits('onDrawStart', AiPlatformEnum.MIDJOURNEY) - // 鍙戦�佽姹� - const imageSize = MidjourneySizeList.find( - (item) => selectSize.value === item.key - ) as ImageSizeVO - const req = { - prompt: prompt.value, - model: selectModel.value, - width: imageSize.width, - height: imageSize.height, - version: selectVersion.value, - referImageUrl: referImageUrl.value - } as ImageMidjourneyImagineReqVO - await ImageApi.midjourneyImagine(req) - } finally { - // 鍥炶皟 - emits('onDrawComplete', AiPlatformEnum.MIDJOURNEY) - // 鍔犺浇缁撴潫 - drawIn.value = false - } -} - -/** 濉厖鍊� */ -const settingValues = async (detail: ImageVO) => { - // 鎻愮ず璇� - prompt.value = detail.prompt - // image size - const imageSize = MidjourneySizeList.find( - (item) => item.key === `${detail.width}:${detail.height}` - ) as ImageSizeVO - selectSize.value = imageSize.key - // 閫変腑妯″瀷 - const model = MidjourneyModels.find((item) => item.key === detail.options?.model) as ImageModelVO - await handleModelClick(model) - // 鐗堟湰 - selectVersion.value = versionList.value.find( - (item) => item.value === detail.options?.version - ).value - // image - referImageUrl.value = detail.options.referImageUrl -} - -/** 鏆撮湶缁勪欢鏂规硶 */ -defineExpose({ settingValues }) -</script> -<style scoped lang="scss"> -// 鎻愮ず璇� -.prompt { -} - -// 鐑瘝 -.hot-words { - display: flex; - flex-direction: column; - margin-top: 30px; - - .word-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: start; - margin-top: 15px; - - .btn { - margin: 0; - } - } -} - -// version -.version { - margin-top: 20px; - - .version-list { - margin-top: 20px; - width: 100%; - } -} - -// 妯″瀷 -.model { - margin-top: 30px; - - .model-list { - margin-top: 15px; - - .modal-item { - display: flex; - flex-direction: column; - align-items: center; - width: 150px; - //outline: 1px solid blue; - overflow: hidden; - border: 3px solid transparent; - cursor: pointer; - - .model-font { - font-size: 14px; - color: #3e3e3e; - font-weight: bold; - } - } - - .selectModel { - border: 3px solid #1293ff; - border-radius: 5px; - } - } -} - -// 灏哄 -.image-size { - width: 100%; - margin-top: 30px; - - .size-list { - display: flex; - flex-direction: row; - justify-content: space-between; - width: 100%; - margin-top: 20px; - - .size-item { - display: flex; - flex-direction: column; - align-items: center; - cursor: pointer; - - .size-wrapper { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - border-radius: 7px; - padding: 4px; - width: 50px; - height: 50px; - background-color: #fff; - border: 1px solid #fff; - } - - .size-font { - font-size: 14px; - color: #3e3e3e; - font-weight: bold; - } - } - } - - .selectImageSize { - border: 1px solid #1293ff !important; - } -} - -.btns { - display: flex; - justify-content: center; - margin-top: 50px; -} -</style> diff --git a/src/views/ai/image/index/components/other/index.vue b/src/views/ai/image/index/components/other/index.vue deleted file mode 100644 index a688be1..0000000 --- a/src/views/ai/image/index/components/other/index.vue +++ /dev/null @@ -1,216 +0,0 @@ -<!-- dall3 --> -<template> - <div class="prompt"> - <el-text tag="b">鐢婚潰鎻忚堪</el-text> - <el-text tag="p">寤鸿浣跨敤鈥滃舰瀹硅瘝+鍔ㄨ瘝+椋庢牸鈥濈殑鏍煎紡锛屼娇鐢ㄢ�滐紝鈥濋殧寮�</el-text> - <el-input - v-model="prompt" - maxlength="1024" - rows="5" - class="w-100% mt-15px" - input-style="border-radius: 7px;" - placeholder="渚嬪锛氱璇濋噷鐨勫皬灞嬪簲璇ユ槸浠�涔堟牱瀛愶紵" - show-word-limit - type="textarea" - /> - </div> - <div class="hot-words"> - <div> - <el-text tag="b">闅忔満鐑瘝</el-text> - </div> - <el-space wrap class="word-list"> - <el-button - round - class="btn" - :type="selectHotWord === hotWord ? 'primary' : 'default'" - v-for="hotWord in ImageHotWords" - :key="hotWord" - @click="handleHotWordClick(hotWord)" - > - {{ hotWord }} - </el-button> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">骞冲彴</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-select - v-model="otherPlatform" - placeholder="Select" - size="large" - class="!w-350px" - @change="handlerPlatformChange" - > - <el-option - v-for="item in OtherPlatformEnum" - :key="item.key" - :label="item.name" - :value="item.key" - /> - </el-select> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">妯″瀷</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-select v-model="model" placeholder="Select" size="large" class="!w-350px"> - <el-option v-for="item in models" :key="item.key" :label="item.name" :value="item.key" /> - </el-select> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">鍥剧墖灏哄</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-input v-model="width" type="number" class="w-170px" placeholder="鍥剧墖瀹藉害" /> - <el-input v-model="height" type="number" class="w-170px" placeholder="鍥剧墖楂樺害" /> - </el-space> - </div> - <div class="btns"> - <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage"> - {{ drawIn ? '鐢熸垚涓�' : '鐢熸垚鍐呭' }} - </el-button> - </div> -</template> -<script setup lang="ts"> -import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image' -import { - AiPlatformEnum, - ChatGlmModels, - ImageHotWords, - ImageModelVO, - OtherPlatformEnum, - QianFanModels, - TongYiWanXiangModels -} from '@/views/ai/utils/constants' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 瀹氫箟灞炴�� -const drawIn = ref<boolean>(false) // 鐢熸垚涓� -const selectHotWord = ref<string>('') // 閫変腑鐨勭儹璇� -// 琛ㄥ崟 -const prompt = ref<string>('') // 鎻愮ず璇� -const width = ref<number>(512) // 鍥剧墖瀹藉害 -const height = ref<number>(512) // 鍥剧墖楂樺害 -const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) // 骞冲彴 -const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // 妯″瀷 TongYiWanXiangModels銆丵ianFanModels -const model = ref<string>(models.value[0].key) // 妯″瀷 - -const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 瀹氫箟 emits - -/** 閫夋嫨鐑瘝 */ -const handleHotWordClick = async (hotWord: string) => { - // 鎯呭喌涓�锛氬彇娑堥�変腑 - if (selectHotWord.value == hotWord) { - selectHotWord.value = '' - return - } - - // 鎯呭喌浜岋細閫変腑 - selectHotWord.value = hotWord // 閫変腑 - prompt.value = hotWord // 鏇挎崲鎻愮ず璇� -} - -/** 鍥剧墖鐢熸垚 */ -const handleGenerateImage = async () => { - // 浜屾纭 - await message.confirm(`纭鐢熸垚鍐呭?`) - try { - // 鍔犺浇涓� - drawIn.value = true - // 鍥炶皟 - emits('onDrawStart', AiPlatformEnum.STABLE_DIFFUSION) - // 鍙戦�佽姹� - const form = { - platform: otherPlatform.value, - model: model.value, // 妯″瀷 - prompt: prompt.value, // 鎻愮ず璇� - width: width.value, // 鍥剧墖瀹藉害 - height: height.value, // 鍥剧墖楂樺害 - options: {} - } as unknown as ImageDrawReqVO - await ImageApi.drawImage(form) - } finally { - // 鍥炶皟 - emits('onDrawComplete', AiPlatformEnum.STABLE_DIFFUSION) - // 鍔犺浇缁撴潫 - drawIn.value = false - } -} - -/** 濉厖鍊� */ -const settingValues = async (detail: ImageVO) => { - prompt.value = detail.prompt - width.value = detail.width - height.value = detail.height -} - -/** 骞冲彴鍒囨崲 */ -const handlerPlatformChange = async (platform: string) => { - // 鍒囨崲骞冲彴锛屽垏鎹㈡ā鍨嬨�侀鏍� - if (AiPlatformEnum.TONG_YI === platform) { - models.value = TongYiWanXiangModels - } else if (AiPlatformEnum.YI_YAN === platform) { - models.value = QianFanModels - } else if (AiPlatformEnum.ZHI_PU === platform) { - models.value = ChatGlmModels - } else { - models.value = [] - } - // 鍒囨崲骞冲彴锛岄粯璁ら�夋嫨涓�涓鏍� - if (models.value.length > 0) { - model.value = models.value[0].key - } else { - model.value = '' - } -} - -/** 鏆撮湶缁勪欢鏂规硶 */ -defineExpose({ settingValues }) -</script> -<style scoped lang="scss"> -// 鎻愮ず璇� -.prompt { -} - -// 鐑瘝 -.hot-words { - display: flex; - flex-direction: column; - margin-top: 30px; - - .word-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: start; - margin-top: 15px; - - .btn { - margin: 0; - } - } -} - -// 妯″瀷 -.group-item { - margin-top: 30px; - - .group-item-body { - margin-top: 15px; - width: 100%; - } -} - -.btns { - display: flex; - justify-content: center; - margin-top: 50px; -} -</style> diff --git a/src/views/ai/image/index/components/stableDiffusion/index.vue b/src/views/ai/image/index/components/stableDiffusion/index.vue deleted file mode 100644 index 169938f..0000000 --- a/src/views/ai/image/index/components/stableDiffusion/index.vue +++ /dev/null @@ -1,272 +0,0 @@ -<!-- dall3 --> -<template> - <div class="prompt"> - <el-text tag="b">鐢婚潰鎻忚堪</el-text> - <el-text tag="p">寤鸿浣跨敤鈥滃舰瀹硅瘝+鍔ㄨ瘝+椋庢牸鈥濈殑鏍煎紡锛屼娇鐢ㄢ�滐紝鈥濋殧寮�</el-text> - <el-input - v-model="prompt" - maxlength="1024" - rows="5" - class="w-100% mt-15px" - input-style="border-radius: 7px;" - placeholder="渚嬪锛氱璇濋噷鐨勫皬灞嬪簲璇ユ槸浠�涔堟牱瀛愶紵" - show-word-limit - type="textarea" - /> - </div> - <div class="hot-words"> - <div> - <el-text tag="b">闅忔満鐑瘝</el-text> - </div> - <el-space wrap class="word-list"> - <el-button - round - class="btn" - :type="selectHotWord === hotWord ? 'primary' : 'default'" - v-for="hotWord in ImageHotEnglishWords" - :key="hotWord" - @click="handleHotWordClick(hotWord)" - > - {{ hotWord }} - </el-button> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">閲囨牱鏂规硶</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-select v-model="sampler" placeholder="Select" size="large" class="!w-350px"> - <el-option - v-for="item in StableDiffusionSamplers" - :key="item.key" - :label="item.name" - :value="item.key" - /> - </el-select> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">CLIP</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-select v-model="clipGuidancePreset" placeholder="Select" size="large" class="!w-350px"> - <el-option - v-for="item in StableDiffusionClipGuidancePresets" - :key="item.key" - :label="item.name" - :value="item.key" - /> - </el-select> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">椋庢牸</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-select v-model="stylePreset" placeholder="Select" size="large" class="!w-350px"> - <el-option - v-for="item in StableDiffusionStylePresets" - :key="item.key" - :label="item.name" - :value="item.key" - /> - </el-select> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">鍥剧墖灏哄</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-input v-model="width" class="w-170px" placeholder="鍥剧墖瀹藉害" /> - <el-input v-model="height" class="w-170px" placeholder="鍥剧墖楂樺害" /> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">杩唬姝ユ暟</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-input - v-model="steps" - type="number" - size="large" - class="!w-350px" - placeholder="Please input" - /> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">寮曞绯绘暟</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-input - v-model="scale" - type="number" - size="large" - class="!w-350px" - placeholder="Please input" - /> - </el-space> - </div> - <div class="group-item"> - <div> - <el-text tag="b">闅忔満鍥犲瓙</el-text> - </div> - <el-space wrap class="group-item-body"> - <el-input - v-model="seed" - type="number" - size="large" - class="!w-350px" - placeholder="Please input" - /> - </el-space> - </div> - <div class="btns"> - <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage"> - {{ drawIn ? '鐢熸垚涓�' : '鐢熸垚鍐呭' }} - </el-button> - </div> -</template> -<script setup lang="ts"> -import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image' -import { hasChinese } from '@/views/ai/utils/utils' -import { - AiPlatformEnum, - ImageHotEnglishWords, - StableDiffusionClipGuidancePresets, - StableDiffusionSamplers, - StableDiffusionStylePresets -} from '@/views/ai/utils/constants' - -const message = useMessage() // 娑堟伅寮圭獥 - -// 瀹氫箟灞炴�� -const drawIn = ref<boolean>(false) // 鐢熸垚涓� -const selectHotWord = ref<string>('') // 閫変腑鐨勭儹璇� -// 琛ㄥ崟 -const prompt = ref<string>('') // 鎻愮ず璇� -const width = ref<number>(512) // 鍥剧墖瀹藉害 -const height = ref<number>(512) // 鍥剧墖楂樺害 -const sampler = ref<string>('DDIM') // 閲囨牱鏂规硶 -const steps = ref<number>(20) // 杩唬姝ユ暟 -const seed = ref<number>(42) // 鎺у埗鐢熸垚鍥惧儚鐨勯殢鏈烘�� -const scale = ref<number>(7.5) // 寮曞绯绘暟 -const clipGuidancePreset = ref<string>('NONE') // 鏂囨湰鎻愮ず鐩稿尮閰嶇殑鍥惧儚(clip_guidance_preset) 绠�绉� CLIP -const stylePreset = ref<string>('3d-model') // 椋庢牸 - -const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 瀹氫箟 emits - -/** 閫夋嫨鐑瘝 */ -const handleHotWordClick = async (hotWord: string) => { - // 鎯呭喌涓�锛氬彇娑堥�変腑 - if (selectHotWord.value == hotWord) { - selectHotWord.value = '' - return - } - - // 鎯呭喌浜岋細閫変腑 - selectHotWord.value = hotWord // 閫変腑 - prompt.value = hotWord // 鏇挎崲鎻愮ず璇� -} - -/** 鍥剧墖鐢熸垚 */ -const handleGenerateImage = async () => { - // 浜屾纭 - if (hasChinese(prompt.value)) { - message.alert('鏆備笉鏀寔涓枃锛�') - return - } - await message.confirm(`纭鐢熸垚鍐呭?`) - - try { - // 鍔犺浇涓� - drawIn.value = true - // 鍥炶皟 - emits('onDrawStart', AiPlatformEnum.STABLE_DIFFUSION) - // 鍙戦�佽姹� - const form = { - platform: AiPlatformEnum.STABLE_DIFFUSION, - model: 'stable-diffusion-v1-6', - prompt: prompt.value, // 鎻愮ず璇� - width: width.value, // 鍥剧墖瀹藉害 - height: height.value, // 鍥剧墖楂樺害 - options: { - seed: seed.value, // 闅忔満绉嶅瓙 - steps: steps.value, // 鍥剧墖鐢熸垚姝ユ暟 - scale: scale.value, // 寮曞绯绘暟 - sampler: sampler.value, // 閲囨牱绠楁硶 - clipGuidancePreset: clipGuidancePreset.value, // 鏂囨湰鎻愮ず鐩稿尮閰嶇殑鍥惧儚 CLIP - stylePreset: stylePreset.value // 椋庢牸 - } - } as ImageDrawReqVO - await ImageApi.drawImage(form) - } finally { - // 鍥炶皟 - emits('onDrawComplete', AiPlatformEnum.STABLE_DIFFUSION) - // 鍔犺浇缁撴潫 - drawIn.value = false - } -} - -/** 濉厖鍊� */ -const settingValues = async (detail: ImageVO) => { - prompt.value = detail.prompt - width.value = detail.width - height.value = detail.height - seed.value = detail.options?.seed - steps.value = detail.options?.steps - scale.value = detail.options?.scale - sampler.value = detail.options?.sampler - clipGuidancePreset.value = detail.options?.clipGuidancePreset - stylePreset.value = detail.options?.stylePreset -} - -/** 鏆撮湶缁勪欢鏂规硶 */ -defineExpose({ settingValues }) -</script> -<style scoped lang="scss"> -// 鎻愮ず璇� -.prompt { -} - -// 鐑瘝 -.hot-words { - display: flex; - flex-direction: column; - margin-top: 30px; - - .word-list { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: start; - margin-top: 15px; - - .btn { - margin: 0; - } - } -} - -// 妯″瀷 -.group-item { - margin-top: 30px; - - .group-item-body { - margin-top: 15px; - width: 100%; - } -} - -.btns { - display: flex; - justify-content: center; - margin-top: 50px; -} -</style> diff --git a/src/views/ai/image/index/index.vue b/src/views/ai/image/index/index.vue deleted file mode 100644 index 1217e79..0000000 --- a/src/views/ai/image/index/index.vue +++ /dev/null @@ -1,141 +0,0 @@ -<!-- image --> -<template> - <div class="ai-image"> - <div class="left"> - <div class="segmented"> - <el-segmented v-model="selectPlatform" :options="platformOptions" /> - </div> - <div class="modal-switch-container"> - <Dall3 - v-if="selectPlatform === AiPlatformEnum.OPENAI" - ref="dall3Ref" - @on-draw-start="handleDrawStart" - @on-draw-complete="handleDrawComplete" - /> - <Midjourney v-if="selectPlatform === AiPlatformEnum.MIDJOURNEY" ref="midjourneyRef" /> - <StableDiffusion - v-if="selectPlatform === AiPlatformEnum.STABLE_DIFFUSION" - ref="stableDiffusionRef" - @on-draw-complete="handleDrawComplete" - /> - <Other - v-if="selectPlatform === 'other'" - ref="otherRef" - @on-draw-complete="handleDrawComplete" - /> - </div> - </div> - <div class="main"> - <ImageList ref="imageListRef" @on-regeneration="handleRegeneration" /> - </div> - </div> -</template> - -<script setup lang="ts"> -import ImageList from './components/ImageList.vue' -import { AiPlatformEnum } from '@/views/ai/utils/constants' -import { ImageVO } from '@/api/ai/image' -import Dall3 from './components/dall3/index.vue' -import Midjourney from './components/midjourney/index.vue' -import StableDiffusion from './components/stableDiffusion/index.vue' -import Other from './components/other/index.vue' - -const imageListRef = ref<any>() // image 鍒楄〃 ref -const dall3Ref = ref<any>() // dall3(openai) ref -const midjourneyRef = ref<any>() // midjourney ref -const stableDiffusionRef = ref<any>() // stable diffusion ref -const otherRef = ref<any>() // stable diffusion ref - -// 瀹氫箟灞炴�� -const selectPlatform = ref(AiPlatformEnum.MIDJOURNEY) -const platformOptions = [ - { - label: 'DALL3 缁樼敾', - value: AiPlatformEnum.OPENAI - }, - { - label: 'MJ 缁樼敾', - value: AiPlatformEnum.MIDJOURNEY - }, - { - label: 'Stable Diffusion', - value: AiPlatformEnum.STABLE_DIFFUSION - }, - { - label: '鍏跺畠', - value: 'other' - } -] - -/** 缁樼敾 start */ -const handleDrawStart = async (platform: string) => {} - -/** 缁樼敾 complete */ -const handleDrawComplete = async (platform: string) => { - await imageListRef.value.getImageList() -} - -/** 閲嶆柊鐢熸垚锛氬皢鐢诲浘璇︽儏濉厖鍒板搴斿钩鍙� */ -const handleRegeneration = async (image: ImageVO) => { - // 鍒囨崲骞冲彴 - selectPlatform.value = image.platform - // 鏍规嵁涓嶅悓骞冲彴濉厖 image - await nextTick() - if (image.platform === AiPlatformEnum.MIDJOURNEY) { - midjourneyRef.value.settingValues(image) - } else if (image.platform === AiPlatformEnum.OPENAI) { - dall3Ref.value.settingValues(image) - } else if (image.platform === AiPlatformEnum.STABLE_DIFFUSION) { - stableDiffusionRef.value.settingValues(image) - } - // TODO @fan锛氳矊浼� other 閲嶆柊璁剧疆涓嶈锛� -} -</script> - -<style scoped lang="scss"> -.ai-image { - position: absolute; - left: 0; - right: 0; - bottom: 0; - top: 0; - - display: flex; - flex-direction: row; - height: 100%; - width: 100%; - - .left { - display: flex; - flex-direction: column; - padding: 20px; - width: 350px; - - .segmented { - } - - .segmented .el-segmented { - --el-border-radius-base: 16px; - --el-segmented-item-selected-color: #fff; - background-color: #ececec; - width: 350px; - } - - .modal-switch-container { - height: 100%; - overflow-y: auto; - margin-top: 30px; - } - } - - .main { - flex: 1; - background-color: #fff; - } - - .right { - width: 350px; - background-color: #f7f8fa; - } -} -</style> diff --git a/src/views/ai/image/manager/index.vue b/src/views/ai/image/manager/index.vue deleted file mode 100644 index 84403f3..0000000 --- a/src/views/ai/image/manager/index.vue +++ /dev/null @@ -1,251 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-select - v-model="queryParams.userId" - clearable - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="骞冲彴" prop="platform"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨骞冲彴" clearable class="!w-240px"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="缁樼敾鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨缁樼敾鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.AI_IMAGE_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鏄惁鍙戝竷" prop="publicStatus"> - <el-select - v-model="queryParams.publicStatus" - placeholder="璇烽�夋嫨鏄惁鍙戝竷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" width="180" fixed="left" /> - <el-table-column label="鍥剧墖" align="center" prop="picUrl" width="110px" fixed="left"> - <template #default="{ row }"> - <el-image - class="h-80px w-80px" - lazy - :src="row.picUrl" - :preview-src-list="[row.picUrl]" - preview-teleported - fit="cover" - v-if="row.picUrl?.length > 0" - /> - </template> - </el-table-column> - <el-table-column label="鐢ㄦ埛" align="center" prop="userId" width="180"> - <template #default="scope"> - <span>{{ userList.find((item) => item.id === scope.row.userId)?.nickname }}</span> - </template> - </el-table-column> - <el-table-column label="骞冲彴" align="center" prop="platform" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" /> - </template> - </el-table-column> - <el-table-column label="妯″瀷" align="center" prop="model" width="180" /> - <el-table-column label="缁樼敾鐘舵��" align="center" prop="status" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_IMAGE_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鏄惁鍙戝竷" align="center" prop="publicStatus"> - <template #default="scope"> - <el-switch - v-model="scope.row.publicStatus" - :active-value="true" - :inactive-value="false" - @change="handleUpdatePublicStatusChange(scope.row)" - :disabled="scope.row.status !== AiImageStatusEnum.SUCCESS" - /> - </template> - </el-table-column> - <el-table-column label="鎻愮ず璇�" align="center" prop="prompt" width="180" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="瀹藉害" align="center" prop="width" /> - <el-table-column label="楂樺害" align="center" prop="height" /> - <el-table-column label="閿欒淇℃伅" align="center" prop="errorMessage" /> - <el-table-column label="浠诲姟缂栧彿" align="center" prop="taskId" /> - <el-table-column label="鎿嶄綔" align="center" width="100" fixed="right"> - <template #default="scope"> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:image:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE, getStrDictOptions, getBoolDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { ImageApi, ImageVO } from '@/api/ai/image' -import * as UserApi from '@/api/system/user' -import { AiImageStatusEnum } from '@/views/ai/utils/constants' - -/** AI 缁樼敾 鍒楄〃 */ -defineOptions({ name: 'AiImageManager' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ImageVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: undefined, - platform: undefined, - status: undefined, - publicStatus: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ImageApi.getImagePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ImageApi.deleteImage(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 淇敼鏄惁鍙戝竷 */ -const handleUpdatePublicStatusChange = async (row: ImageVO) => { - try { - // 淇敼鐘舵�佺殑浜屾纭 - const text = row.publicStatus ? '鍏紑' : '绉佹湁' - await message.confirm('纭瑕�"' + text + '"璇ュ浘鐗囧悧?') - // 鍙戣捣淇敼鐘舵�� - await ImageApi.updateImage({ - id: row.id, - publicStatus: row.publicStatus - }) - await getList() - } catch { - row.publicStatus = !row.publicStatus - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/ai/image/square/index.vue b/src/views/ai/image/square/index.vue deleted file mode 100644 index b7885ff..0000000 --- a/src/views/ai/image/square/index.vue +++ /dev/null @@ -1,85 +0,0 @@ -<template> - <div class="square-container"> - <el-input - v-model="searchText" - style="width: 100%; margin-bottom: 20px" - size="large" - placeholder="璇疯緭鍏ヨ鎼滅储鐨勫唴瀹�" - :suffix-icon="Search" - @keyup.enter="handleSearch" - /> - <div class="gallery"> - <div v-for="item in publicList" :key="item.id" class="gallery-item"> - <img :src="item.picUrl" class="img" /> - </div> - </div> - </div> -</template> -<script setup lang="ts"> -import { ImageApi, ImageVO } from '@/api/ai/image' -import { Search } from '@element-plus/icons-vue' - -/** 灞炴�� */ -// TODO @fan锛歲ueryParams 閲岄潰鎼炲垎椤靛搱銆� -const pageNo = ref<number>(1) -const pageSize = ref<number>(20) -const publicList = ref<ImageVO[]>([]) -const searchText = ref<string>('') - -/** 鑾峰彇鏁版嵁 */ -const getListData = async () => { - const res = await ImageApi.getImagePagePublic({ - pageNo: pageNo.value, - pageSize: pageSize.value, - prompt: searchText.value - }) - publicList.value = res.list as ImageVO[] -} - -/** 鎼滅储 */ -const handleSearch = async () => { - await getListData() -} - -onMounted(async () => { - await getListData() -}) -</script> -<style scoped lang="scss"> -.square-container { - background-color: #fff; - padding: 20px; - - .gallery { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 10px; - //max-width: 1000px; - background-color: #fff; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - } - - .gallery-item { - position: relative; - overflow: hidden; - background: #f0f0f0; - cursor: pointer; - transition: transform 0.3s; - } - - .gallery-item img { - width: 100%; - height: auto; - display: block; - transition: transform 0.3s; - } - - .gallery-item:hover img { - transform: scale(1.1); - } - - .gallery-item:hover { - transform: scale(1.05); - } -} -</style> diff --git a/src/views/ai/model/apiKey/ApiKeyForm.vue b/src/views/ai/model/apiKey/ApiKeyForm.vue deleted file mode 100644 index a8fc012..0000000 --- a/src/views/ai/model/apiKey/ApiKeyForm.vue +++ /dev/null @@ -1,132 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="鎵�灞炲钩鍙�" prop="platform"> - <el-select v-model="formData.platform" placeholder="璇疯緭鍏ュ钩鍙�" clearable> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="瀵嗛挜" prop="apiKey"> - <el-input v-model="formData.apiKey" placeholder="璇疯緭鍏ュ瘑閽�" /> - </el-form-item> - <el-form-item label="鑷畾涔� API URL" prop="url"> - <el-input v-model="formData.url" placeholder="璇疯緭鍏ヨ嚜瀹氫箟 API URL" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE, getStrDictOptions } from '@/utils/dict' -import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' -import { CommonStatusEnum } from '@/utils/constants' - -/** AI API 瀵嗛挜 琛ㄥ崟 */ -defineOptions({ name: 'ApiKeyForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - apiKey: undefined, - platform: undefined, - url: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - apiKey: [{ required: true, message: '瀵嗛挜涓嶈兘涓虹┖', trigger: 'blur' }], - platform: [{ required: true, message: '骞冲彴涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ApiKeyApi.getApiKey(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ApiKeyVO - if (formType.value === 'create') { - await ApiKeyApi.createApiKey(data) - message.success(t('common.createSuccess')) - } else { - await ApiKeyApi.updateApiKey(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - apiKey: undefined, - platform: undefined, - url: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/ai/model/apiKey/index.vue b/src/views/ai/model/apiKey/index.vue deleted file mode 100644 index 6daf6a7..0000000 --- a/src/views/ai/model/apiKey/index.vue +++ /dev/null @@ -1,180 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="骞冲彴" prop="platform"> - <el-select - v-model="queryParams.platform" - placeholder="璇疯緭鍏ュ钩鍙�" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['ai:api-key:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鎵�灞炲钩鍙�" align="center" prop="platform"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" /> - </template> - </el-table-column> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="瀵嗛挜" align="center" prop="apiKey" /> - <el-table-column label="鑷畾涔� API URL" align="center" prop="url" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['ai:api-key:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:api-key:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ApiKeyForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE, getStrDictOptions } from '@/utils/dict' -import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' -import ApiKeyForm from './ApiKeyForm.vue' - -/** AI API 瀵嗛挜 鍒楄〃 */ -defineOptions({ name: 'AiApiKey' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ApiKeyVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - platform: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ApiKeyApi.getApiKeyPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ApiKeyApi.deleteApiKey(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/ai/model/chatModel/ChatModelForm.vue b/src/views/ai/model/chatModel/ChatModelForm.vue deleted file mode 100644 index e3f785c..0000000 --- a/src/views/ai/model/chatModel/ChatModelForm.vue +++ /dev/null @@ -1,181 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="鎵�灞炲钩鍙�" prop="platform"> - <el-select v-model="formData.platform" placeholder="璇疯緭鍏ュ钩鍙�" clearable> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="API 绉橀挜" prop="keyId"> - <el-select v-model="formData.keyId" placeholder="璇烽�夋嫨 API 绉橀挜" clearable> - <el-option - v-for="apiKey in apiKeyList" - :key="apiKey.id" - :label="apiKey.name" - :value="apiKey.id" - /> - </el-select> - </el-form-item> - <el-form-item label="妯″瀷鍚嶅瓧" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ユā鍨嬪悕瀛�" /> - </el-form-item> - <el-form-item label="妯″瀷鏍囪瘑" prop="model"> - <el-input v-model="formData.model" placeholder="璇疯緭鍏ユā鍨嬫爣璇�" /> - </el-form-item> - <el-form-item label="妯″瀷鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" placeholder="璇疯緭鍏ユā鍨嬫帓搴�" class="!w-1/1" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="娓╁害鍙傛暟" prop="temperature"> - <el-input-number - v-model="formData.temperature" - placeholder="璇疯緭鍏ユ俯搴﹀弬鏁�" - :min="0" - :max="2" - :precision="2" - /> - </el-form-item> - <el-form-item label="鍥炲鏁� Token 鏁�" prop="maxTokens"> - <el-input-number - v-model="formData.maxTokens" - placeholder="璇疯緭鍏ュ洖澶嶆暟 Token 鏁�" - :min="0" - :max="4096" - /> - </el-form-item> - <el-form-item label="涓婁笅鏂囨暟閲�" prop="maxContexts"> - <el-input-number - v-model="formData.maxContexts" - placeholder="璇疯緭鍏ヤ笂涓嬫枃鏁伴噺" - :min="0" - :max="20" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' -import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' - -/** API 鑱婂ぉ妯″瀷 琛ㄥ崟 */ -defineOptions({ name: 'ChatModelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - keyId: undefined, - name: undefined, - model: undefined, - platform: undefined, - sort: undefined, - status: CommonStatusEnum.ENABLE, - temperature: undefined, - maxTokens: undefined, - maxContexts: undefined -}) -const formRules = reactive({ - keyId: [{ required: true, message: 'API 绉橀挜涓嶈兘涓虹┖', trigger: 'blur' }], - name: [{ required: true, message: '妯″瀷鍚嶅瓧涓嶈兘涓虹┖', trigger: 'blur' }], - model: [{ required: true, message: '妯″瀷鏍囪瘑涓嶈兘涓虹┖', trigger: 'blur' }], - platform: [{ required: true, message: '鎵�灞炲钩鍙颁笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const apiKeyList = ref([] as ApiKeyVO[]) // API 瀵嗛挜鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ChatModelApi.getChatModel(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱涓嬫媺鏁版嵁 - apiKeyList.value = await ApiKeyApi.getApiKeySimpleList(CommonStatusEnum.ENABLE) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ChatModelVO - if (formType.value === 'create') { - await ChatModelApi.createChatModel(data) - message.success(t('common.createSuccess')) - } else { - await ChatModelApi.updateChatModel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - keyId: undefined, - name: undefined, - model: undefined, - platform: undefined, - sort: undefined, - status: CommonStatusEnum.ENABLE, - temperature: undefined, - maxTokens: undefined, - maxContexts: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/ai/model/chatModel/index.vue b/src/views/ai/model/chatModel/index.vue deleted file mode 100644 index c550674..0000000 --- a/src/views/ai/model/chatModel/index.vue +++ /dev/null @@ -1,185 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="妯″瀷鍚嶅瓧" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユā鍨嬪悕瀛�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="妯″瀷鏍囪瘑" prop="model"> - <el-input - v-model="queryParams.model" - placeholder="璇疯緭鍏ユā鍨嬫爣璇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="妯″瀷骞冲彴" prop="platform"> - <el-input - v-model="queryParams.platform" - placeholder="璇疯緭鍏ユā鍨嬪钩鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['ai:chat-model:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鎵�灞炲钩鍙�" align="center" prop="platform"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" /> - </template> - </el-table-column> - <el-table-column label="妯″瀷鍚嶅瓧" align="center" prop="name" /> - <el-table-column label="妯″瀷鏍囪瘑" align="center" prop="model" /> - <el-table-column label="API 绉橀挜" align="center" prop="keyId" min-width="140"> - <template #default="scope"> - <span>{{ apiKeyList.find((item) => item.id === scope.row.keyId)?.name }}</span> - </template> - </el-table-column> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="娓╁害鍙傛暟" align="center" prop="temperature" /> - <el-table-column label="鍥炲鏁� Token 鏁�" align="center" prop="maxTokens" min-width="140" /> - <el-table-column label="涓婁笅鏂囨暟閲�" align="center" prop="maxContexts" /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['ai:chat-model:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:chat-model:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ChatModelForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' -import ChatModelForm from './ChatModelForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' - -/** API 鑱婂ぉ妯″瀷 鍒楄〃 */ -defineOptions({ name: 'AiChatModel' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ChatModelVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - model: undefined, - platform: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const apiKeyList = ref([] as ApiKeyVO[]) // API 瀵嗛挜鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ChatModelApi.getChatModelPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ChatModelApi.deleteChatModel(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱涓嬫媺鏁版嵁 - apiKeyList.value = await ApiKeyApi.getApiKeySimpleList() -}) -</script> diff --git a/src/views/ai/model/chatRole/ChatRoleForm.vue b/src/views/ai/model/chatRole/ChatRoleForm.vue deleted file mode 100644 index 3c49e8e..0000000 --- a/src/views/ai/model/chatRole/ChatRoleForm.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="瑙掕壊鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ヨ鑹插悕绉�" /> - </el-form-item> - <el-form-item label="瑙掕壊澶村儚" prop="avatar"> - <UploadImg v-model="formData.avatar" height="60px" width="60px" /> - </el-form-item> - <el-form-item label="缁戝畾妯″瀷" prop="modelId" v-if="!isUser"> - <el-select v-model="formData.modelId" placeholder="璇烽�夋嫨妯″瀷" clearable> - <el-option - v-for="chatModel in chatModelList" - :key="chatModel.id" - :label="chatModel.name" - :value="chatModel.id" - /> - </el-select> - </el-form-item> - <el-form-item label="瑙掕壊绫诲埆" prop="category" v-if="!isUser"> - <el-input v-model="formData.category" placeholder="璇疯緭鍏ヨ鑹茬被鍒�" /> - </el-form-item> - <el-form-item label="瑙掕壊鎻忚堪" prop="description"> - <el-input type="textarea" v-model="formData.description" placeholder="璇疯緭鍏ヨ鑹叉弿杩�" /> - </el-form-item> - <el-form-item label="瑙掕壊璁惧畾" prop="systemMessage"> - <el-input type="textarea" v-model="formData.systemMessage" placeholder="璇疯緭鍏ヨ鑹茶瀹�" /> - </el-form-item> - <el-form-item label="鏄惁鍏紑" prop="publicStatus" v-if="!isUser"> - <el-radio-group v-model="formData.publicStatus"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="瑙掕壊鎺掑簭" prop="sort" v-if="!isUser"> - <el-input-number v-model="formData.sort" placeholder="璇疯緭鍏ヨ鑹叉帓搴�" class="!w-1/1" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status" v-if="!isUser"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import { ChatRoleApi, ChatRoleVO } from '@/api/ai/model/chatRole' -import { CommonStatusEnum } from '@/utils/constants' -import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' -import {FormRules} from "element-plus"; - -/** AI 鑱婂ぉ瑙掕壊 琛ㄥ崟 */ -defineOptions({ name: 'ChatRoleForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - modelId: undefined, - name: undefined, - avatar: undefined, - category: undefined, - sort: undefined, - description: undefined, - systemMessage: undefined, - publicStatus: true, - status: CommonStatusEnum.ENABLE -}) -const formRef = ref() // 琛ㄥ崟 Ref -const chatModelList = ref([] as ChatModelVO[]) // 鑱婂ぉ妯″瀷鍒楄〃 - -/** 鏄惁銆愭垜銆戣嚜宸卞垱寤猴紝绉佹湁瑙掕壊 */ -const isUser = computed(() => { - return formType.value === 'my-create' || formType.value === 'my-update' -}) - -const formRules = reactive<FormRules>({ - name: [{ required: true, message: '瑙掕壊鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - avatar: [{ required: true, message: '瑙掕壊澶村儚涓嶈兘涓虹┖', trigger: 'blur' }], - category: [{ required: true, message: '瑙掕壊绫诲埆涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '瑙掕壊鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - description: [{ required: true, message: '瑙掕壊鎻忚堪涓嶈兘涓虹┖', trigger: 'blur' }], - systemMessage: [{ required: true, message: '瑙掕壊璁惧畾涓嶈兘涓虹┖', trigger: 'blur' }], - publicStatus: [{ required: true, message: '鏄惁鍏紑涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -/** 鎵撳紑寮圭獥 */ -// TODO @fan锛歵itle 鏄笉鏄敹鏁涘埌 type 鍒ゆ柇鐢熸垚 title锛屼細鏇村悎鐞� -const open = async (type: string, id?: number, title?: string) => { - dialogVisible.value = true - dialogTitle.value = title || t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ChatRoleApi.getChatRole(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱涓嬫媺鏁版嵁 - chatModelList.value = await ChatModelApi.getChatModelSimpleList(CommonStatusEnum.ENABLE) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ChatRoleVO - // tip: my-create銆乵y-update 鏄� chat 瑙掕壊浠撳簱璋冪敤 - // tip: create銆乪lse 鏄悗鍙扮鐞嗚皟鐢� - if (formType.value === 'my-create') { - await ChatRoleApi.createMy(data) - message.success(t('common.createSuccess')) - } else if (formType.value === 'my-update') { - await ChatRoleApi.updateMy(data) - message.success(t('common.updateSuccess')) - } else if (formType.value === 'create') { - await ChatRoleApi.createChatRole(data) - message.success(t('common.createSuccess')) - } else { - await ChatRoleApi.updateChatRole(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - modelId: undefined, - name: undefined, - avatar: undefined, - category: undefined, - sort: undefined, - description: undefined, - systemMessage: undefined, - publicStatus: true, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/ai/model/chatRole/index.vue b/src/views/ai/model/chatRole/index.vue deleted file mode 100644 index e870a55..0000000 --- a/src/views/ai/model/chatRole/index.vue +++ /dev/null @@ -1,187 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="瑙掕壊鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ヨ鑹插悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="瑙掕壊绫诲埆" prop="category"> - <el-input - v-model="queryParams.category" - placeholder="璇疯緭鍏ヨ鑹茬被鍒�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鏄惁鍏紑" prop="publicStatus"> - <el-select - v-model="queryParams.publicStatus" - placeholder="璇烽�夋嫨鏄惁鍏紑" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['ai:chat-role:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="瑙掕壊鍚嶇О" align="center" prop="name" /> - <el-table-column label="缁戝畾妯″瀷" align="center" prop="modelName" /> - <el-table-column label="瑙掕壊澶村儚" align="center" prop="avatar"> - <template #default="scope"> - <el-image :src="scope?.row.avatar" class="w-32px h-32px" /> - </template> - </el-table-column> - <el-table-column label="瑙掕壊绫诲埆" align="center" prop="category" /> - <el-table-column label="瑙掕壊鎻忚堪" align="center" prop="description" /> - <el-table-column label="瑙掕壊璁惧畾" align="center" prop="systemMessage" /> - <el-table-column label="鏄惁鍏紑" align="center" prop="publicStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.publicStatus" /> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="瑙掕壊鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['ai:chat-role:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:chat-role:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ChatRoleForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import { ChatRoleApi, ChatRoleVO } from '@/api/ai/model/chatRole' -import ChatRoleForm from './ChatRoleForm.vue' - -/** AI 鑱婂ぉ瑙掕壊 鍒楄〃 */ -defineOptions({ name: 'AiChatRole' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ChatRoleVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - category: undefined, - publicStatus: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ChatRoleApi.getChatRolePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ChatRoleApi.deleteChatRole(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/ai/music/components/index.vue b/src/views/ai/music/components/index.vue deleted file mode 100644 index 413792a..0000000 --- a/src/views/ai/music/components/index.vue +++ /dev/null @@ -1,26 +0,0 @@ -<template> -<div class="flex h-full items-stretch"> - <!-- 妯″紡 --> - <Mode class="flex-none" @generate-music="generateMusic"/> - <!-- 闊抽鍒楄〃 --> - <List ref="listRef" class="flex-auto"/> - </div> -</template> - -<script lang="ts" setup> -import Mode from './mode/index.vue' -import List from './list/index.vue' - -defineOptions({ name: 'Index' }) - -const listRef = ref<Nullable<{generateMusic: (...args) => void}>>(null) - -/* - *@Description: 鎷垮埌宸︿晶閰嶇疆淇℃伅璋冪敤鍙充晶闊充箰鐢熸垚鐨勬柟娉� - *@MethodAuthor: xiaohong - *@Date: 2024-07-19 11:13:38 -*/ -function generateMusic (args: {formData: Recordable}) { - unref(listRef)?.generateMusic(args.formData) -} -</script> diff --git a/src/views/ai/music/components/list/audioBar/index.vue b/src/views/ai/music/components/list/audioBar/index.vue deleted file mode 100644 index db7f767..0000000 --- a/src/views/ai/music/components/list/audioBar/index.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <div class="flex items-center justify-between px-2 h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none"> - <!-- 姝屾洸淇℃伅 --> - <div class="flex gap-[10px]"> - <el-image src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" class="w-[45px]"/> - <div> - <div>{{currentSong.name}}</div> - <div class="text-[12px] text-gray-400">{{currentSong.singer}}</div> - </div> - </div> - - <!-- 闊抽controls --> - <div class="flex gap-[12px] items-center"> - <Icon icon="majesticons:back-circle" :size="20" class="text-gray-300 cursor-pointer"/> - <Icon :icon="audioProps.paused ? 'mdi:arrow-right-drop-circle' : 'solar:pause-circle-bold'" :size="30" class=" cursor-pointer" @click="toggleStatus('paused')"/> - <Icon icon="majesticons:next-circle" :size="20" class="text-gray-300 cursor-pointer"/> - <div class="flex gap-[16px] items-center"> - <span>{{audioProps.currentTime}}</span> - <el-slider v-model="audioProps.duration" color="#409eff" class="w-[160px!important] "/> - <span>{{ audioProps.duration }}</span> - </div> - <!-- 闊抽 --> - <audio v-bind="audioProps" ref="audioRef" controls v-show="!audioProps" @timeupdate="audioTimeUpdate"> - <source :src="audioUrl"/> - </audio> - </div> - - <!-- 闊抽噺鎺у埗鍣� --> - <div class="flex gap-[16px] items-center"> - <Icon :icon="audioProps.muted ? 'tabler:volume-off' : 'tabler:volume'" :size="20" class="cursor-pointer" @click="toggleStatus('muted')"/> - <el-slider v-model="audioProps.volume" color="#409eff" class="w-[160px!important] "/> - </div> - </div> -</template> - -<script lang="ts" setup> -import { formatPast } from '@/utils/formatTime' -import audioUrl from '@/assets/audio/response.mp3' - -defineOptions({ name: 'Index' }) - -const currentSong = inject('currentSong', {}) - -const audioRef = ref<Nullable<HTMLElement>>(null) - // 闊抽鐩稿叧灞炴�ttps://www.runoob.com/tags/ref-av-dom.html -const audioProps = reactive({ - autoplay: true, - paused: false, - currentTime: '00:00', - duration: '00:00', - muted: false, - volume: 50, -}) - -function toggleStatus (type: string) { - audioProps[type] = !audioProps[type] - if (type === 'paused' && audioRef.value) { - if (audioProps[type]) { - audioRef.value.pause() - } else { - audioRef.value.play() - } - } -} - -// 鏇存柊鎾斁浣嶇疆 -function audioTimeUpdate (args) { - audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss') -} -</script> diff --git a/src/views/ai/music/components/list/index.vue b/src/views/ai/music/components/list/index.vue deleted file mode 100644 index 6c33f56..0000000 --- a/src/views/ai/music/components/list/index.vue +++ /dev/null @@ -1,108 +0,0 @@ -<template> - <div class="flex flex-col"> - <div class="flex-auto flex overflow-hidden"> - <el-tabs v-model="currentType" class="flex-auto px-[var(--app-content-padding)]"> - <!-- 鎴戠殑鍒涗綔 --> - <el-tab-pane v-loading="loading" label="鎴戠殑鍒涗綔" name="mine"> - <el-row v-if="mySongList.length" :gutter="12"> - <el-col v-for="song in mySongList" :key="song.id" :span="24"> - <songCard :songInfo="song" @play="setCurrentSong(song)"/> - </el-col> - </el-row> - <el-empty v-else description="鏆傛棤闊充箰"/> - </el-tab-pane> - - <!-- 璇曞惉骞垮満 --> - <el-tab-pane v-loading="loading" label="璇曞惉骞垮満" name="square"> - <el-row v-if="squareSongList.length" v-loading="loading" :gutter="12"> - <el-col v-for="song in squareSongList" :key="song.id" :span="24"> - <songCard :songInfo="song" @play="setCurrentSong(song)"/> - </el-col> - </el-row> - <el-empty v-else description="鏆傛棤闊充箰"/> - </el-tab-pane> - </el-tabs> - <!-- songInfo --> - <songInfo class="flex-none"/> - </div> - <audioBar class="flex-none"/> - </div> -</template> - -<script lang="ts" setup> -import songCard from './songCard/index.vue' -import songInfo from './songInfo/index.vue' -import audioBar from './audioBar/index.vue' - -defineOptions({ name: 'Index' }) - - -const currentType = ref('mine') -// loading 鐘舵�� -const loading = ref(false) -// 褰撳墠闊充箰 -const currentSong = ref({}) - -const mySongList = ref<Recordable[]>([]) -const squareSongList = ref<Recordable[]>([]) - -provide('currentSong', currentSong) - -/* - *@Description: 璋冩帴鍙g敓鎴愰煶涔愬垪琛� - *@MethodAuthor: xiaohong - *@Date: 2024-06-27 17:06:44 -*/ -function generateMusic (formData: Recordable) { - console.log(formData); - loading.value = true - setTimeout(() => { - mySongList.value = Array.from({ length: 20 }, (_, index) => { - return { - id: index, - audioUrl: '', - videoUrl: '', - title: '鎴戣蛋鍚�' + index, - imageUrl: 'https://www.carsmp3.com/data/attachment/forum/201909/19/091020q5kgre20fidreqyt.jpg', - desc: 'Metal, symphony, film soundtrack, grand, majesticMetal, dtrack, grand, majestic', - date: '2024骞�04鏈�30鏃� 14:02:57', - lyric: `<div class="_words_17xen_66"><div>澶ф睙涓滃幓锛屾氮娣樺敖锛屽崈鍙ら娴佷汉鐗┿�� - </div><div>鏁呭瀿瑗胯竟锛屼汉閬撴槸锛屼笁鍥藉懆閮庤丹澹併�� - </div><div>涔辩煶绌跨┖锛屾儕娑涙媿宀革紝鍗疯捣鍗冨爢闆�� - </div><div>姹熷北濡傜敾锛屼竴鏃跺灏戣豹鏉般�� - </div><div> - </div><div>閬ユ兂鍏懢褰撳勾锛屽皬涔斿垵瀚佷簡锛岄泟濮胯嫳鍙戙�� - </div><div>缇芥墖绾跺肪锛岃皥绗戦棿锛屾ǒ姗圭伆椋炵儫鐏�� - </div><div>鏁呭浗绁炴父锛屽鎯呭簲绗戞垜锛屾棭鐢熷崕鍙戙�� - </div><div>浜虹敓濡傛ⅵ锛屼竴灏婅繕閰规睙鏈堛��</div></div>` - } - }) - loading.value = false - }, 3000) -} - -/* - *@Description: 璁剧疆褰撳墠鎾斁鐨勯煶涔� - *@MethodAuthor: xiaohong - *@Date: 2024-07-19 11:22:33 -*/ -function setCurrentSong (music: Recordable) { - currentSong.value = music -} - -defineExpose({ - generateMusic -}) -</script> - - -<style lang="scss" scoped> -:deep(.el-tabs) { - display: flex; - flex-direction: column; - .el-tabs__content { - padding: 0 7px; - overflow: auto; - } -} -</style> diff --git a/src/views/ai/music/components/list/songCard/index.vue b/src/views/ai/music/components/list/songCard/index.vue deleted file mode 100644 index 0534251..0000000 --- a/src/views/ai/music/components/list/songCard/index.vue +++ /dev/null @@ -1,36 +0,0 @@ -<template> - <div class="flex bg-[var(--el-bg-color-overlay)] p-12px mb-12px rounded-1"> - <div class="relative" @click="playSong"> - <el-image :src="songInfo.imageUrl" class="flex-none w-80px"/> - <div class="bg-black bg-op-40 absolute top-0 left-0 w-full h-full flex items-center justify-center cursor-pointer"> - <Icon :icon="currentSong.id === songInfo.id ? 'solar:pause-circle-bold':'mdi:arrow-right-drop-circle'" :size="30" /> - </div> - </div> - <div class="ml-8px"> - <div>{{ songInfo.title }}</div> - <div class="mt-8px text-12px text-[var(--el-text-color-secondary)] line-clamp-2"> - {{ songInfo.desc }} - </div> - </div> - </div> -</template> - -<script lang="ts" setup> - -defineOptions({ name: 'Index' }) - -defineProps({ - songInfo: { - type: Object, - default: () => ({}) - } -}) - -const emits = defineEmits(['play']) - -const currentSong = inject('currentSong', {}) - -function playSong () { - emits('play') -} -</script> diff --git a/src/views/ai/music/components/list/songInfo/index.vue b/src/views/ai/music/components/list/songInfo/index.vue deleted file mode 100644 index 8d67c4d..0000000 --- a/src/views/ai/music/components/list/songInfo/index.vue +++ /dev/null @@ -1,22 +0,0 @@ -<template> - <ContentWrap class="w-300px mb-[0!important] line-height-24px"> - <el-image :src="currentSong.imageUrl"/> - <div class="">{{ currentSong.title }}</div> - <div class="text-[var(--el-text-color-secondary)] text-12px line-clamp-1"> - {{ currentSong.desc }} - </div> - <div class="text-[var(--el-text-color-secondary)] text-12px"> - {{ currentSong.date }} - </div> - <el-button size="small" round class="my-6px">淇℃伅澶嶇敤</el-button> - <div class="text-[var(--el-text-color-secondary)] text-12px" v-html="currentSong.lyric"></div> - </ContentWrap> -</template> - -<script lang="ts" setup> - -defineOptions({ name: 'Index' }) - -const currentSong = inject('currentSong', {}) - -</script> diff --git a/src/views/ai/music/components/mode/desc.vue b/src/views/ai/music/components/mode/desc.vue deleted file mode 100644 index 4488461..0000000 --- a/src/views/ai/music/components/mode/desc.vue +++ /dev/null @@ -1,55 +0,0 @@ -<template> - <div> - <Title title="闊充箰/姝岃瘝璇存槑" desc="鎻忚堪鎮ㄦ兂瑕佺殑闊充箰椋庢牸鍜屼富棰橈紝浣跨敤娴佹淳鍜屾皼鍥磋�屼笉鏄壒瀹氱殑鑹烘湳瀹跺拰姝屾洸"> - <el-input - v-model="formData.desc" - :autosize="{ minRows: 6, maxRows: 6}" - resize="none" - type="textarea" - maxlength="1200" - show-word-limit - placeholder="涓�棣栧叧浜庣碂绯曞垎鎵嬬殑娆㈠揩姝屾洸" - /> - </Title> - - <Title title="绾煶涔�" desc="鍒涘缓涓�棣栨病鏈夋瓕璇嶇殑姝屾洸"> - <template #extra> - <el-switch v-model="formData.pure" size="small"/> - </template> - </Title> - - <Title title="鐗堟湰" desc="鎻忚堪鎮ㄦ兂瑕佺殑闊充箰椋庢牸鍜屼富棰橈紝浣跨敤娴佹淳鍜屾皼鍥磋�屼笉鏄壒瀹氱殑鑹烘湳瀹跺拰姝屾洸"> - <el-select v-model="formData.version" placeholder="璇烽�夋嫨"> - <el-option - v-for="item in [{ - value: '3', - label: 'V3' - }, { - value: '2', - label: 'V2' - }]" - :key="item.value" - :label="item.label" - :value="item.value" - /> - </el-select> - </Title> - </div> -</template> - -<script lang="ts" setup> -import Title from '../title/index.vue' - -defineOptions({ name: 'Desc' }) - -const formData = reactive({ - desc: '', - pure: false, - version: '3' -}) - -defineExpose({ - formData -}) - -</script> diff --git a/src/views/ai/music/components/mode/index.vue b/src/views/ai/music/components/mode/index.vue deleted file mode 100644 index 85ef893..0000000 --- a/src/views/ai/music/components/mode/index.vue +++ /dev/null @@ -1,41 +0,0 @@ -<template> - <ContentWrap class="w-300px h-full mb-[0!important]"> - <el-radio-group v-model="generateMode" class="mb-15px"> - <el-radio-button label="desc"> - 鎻忚堪妯″紡 - </el-radio-button> - <el-radio-button label="lyric"> - 姝岃瘝妯″紡 - </el-radio-button> - </el-radio-group> - - <!-- 鎻忚堪妯″紡/姝岃瘝妯″紡 鍒囨崲 --> - <component :is="generateMode === 'desc' ? desc : lyric" ref="modeRef"/> - - <el-button type="primary" round class="w-full" @click="generateMusic"> - 鍒涗綔闊充箰 - </el-button> - </ContentWrap> -</template> - -<script lang="ts" setup> -import desc from './desc.vue' -import lyric from './lyric.vue' - -defineOptions({ name: 'Index' }) - -const emits = defineEmits(['generate-music']) - -const generateMode = ref('lyric') - -const modeRef = ref<Nullable<{ formData: Recordable }>>(null) - -/* - *@Description: 鏍规嵁淇℃伅鐢熸垚闊充箰 - *@MethodAuthor: xiaohong - *@Date: 2024-06-27 16:40:16 -*/ -function generateMusic () { - emits('generate-music', {formData: unref(modeRef)?.formData}) -} -</script> diff --git a/src/views/ai/music/components/mode/lyric.vue b/src/views/ai/music/components/mode/lyric.vue deleted file mode 100644 index f774003..0000000 --- a/src/views/ai/music/components/mode/lyric.vue +++ /dev/null @@ -1,83 +0,0 @@ -<template> - <div class=""> - <Title title="姝岃瘝" desc="鑷繁缂栧啓姝岃瘝鎴栦娇鐢ˋi鐢熸垚姝岃瘝锛屼袱鑺�/8琛屾晥鏋滄渶浣�"> - <el-input - v-model="formData.lyric" - :autosize="{ minRows: 6, maxRows: 6}" - resize="none" - type="textarea" - maxlength="1200" - show-word-limit - placeholder="璇疯緭鍏ユ偍鑷繁鐨勬瓕璇�" - /> - </Title> - - <Title title="闊充箰椋庢牸"> - <el-space class="flex-wrap"> - <el-tag v-for="tag in tags" :key="tag" round class="mb-8px">{{tag}}</el-tag> - </el-space> - - <el-button - :type="showCustom ? 'primary': 'default'" - round - size="small" - class="mb-6px" - @click="showCustom = !showCustom" - >鑷畾涔夐鏍� - </el-button> - </Title> - - <Title v-show="showCustom" desc="鎻忚堪鎮ㄦ兂瑕佺殑闊充箰椋庢牸锛孲uno鏃犳硶璇嗗埆鑹烘湳瀹剁殑鍚嶅瓧锛屼絾鍙互鐞嗚В娴佹淳鍜屾皼鍥�" class="-mt-12px"> - <el-input - v-model="formData.style" - :autosize="{ minRows: 4, maxRows: 4}" - resize="none" - type="textarea" - maxlength="256" - show-word-limit - placeholder="杈撳叆闊充箰椋庢牸(鑻辨枃)" - /> - </Title> - - <Title title="闊充箰/姝屾洸鍚嶇О"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ラ煶涔�/姝屾洸鍚嶇О"/> - </Title> - - <Title title="鐗堟湰"> - <el-select v-model="formData.version" placeholder="璇烽�夋嫨"> - <el-option - v-for="item in [{ - value: '3', - label: 'V3' - }, { - value: '2', - label: 'V2' - }]" - :key="item.value" - :label="item.label" - :value="item.value" - /> - </el-select> - </Title> - </div> -</template> - -<script lang="ts" setup> -import Title from '../title/index.vue' -defineOptions({ name: 'Lyric' }) - -const tags = ['rock', 'punk', 'jazz', 'soul', 'country', 'kidsmusic', 'pop'] - -const showCustom = ref(false) - -const formData = reactive({ - lyric: '', - style: '', - name: '', - version: '' -}) - -defineExpose({ - formData -}) -</script> diff --git a/src/views/ai/music/components/title/index.vue b/src/views/ai/music/components/title/index.vue deleted file mode 100644 index a065802..0000000 --- a/src/views/ai/music/components/title/index.vue +++ /dev/null @@ -1,25 +0,0 @@ -<template> - <div class="mb-12px"> - <div class="flex text-[var(--el-text-color-primary)] justify-between items-center"> - <span>{{title}}</span> - <slot name="extra"></slot> - </div> - <div class="text-[var(--el-text-color-secondary)] text-12px my-8px"> - {{desc}} - </div> - <slot></slot> - </div> -</template> - -<script lang="ts" setup> -defineOptions({ name: 'Index' }) - -defineProps({ - title: { - type: String - }, - desc: { - type: String - } -}) -</script> diff --git a/src/views/ai/music/manager/index.vue b/src/views/ai/music/manager/index.vue deleted file mode 100644 index 462a88d..0000000 --- a/src/views/ai/music/manager/index.vue +++ /dev/null @@ -1,292 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-select - v-model="queryParams.userId" - clearable - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="闊充箰鍚嶇О" prop="title"> - <el-input - v-model="queryParams.title" - placeholder="璇疯緭鍏ラ煶涔愬悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="闊充箰鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨闊充箰鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.AI_MUSIC_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐢熸垚妯″紡" prop="generateMode"> - <el-select - v-model="queryParams.generateMode" - placeholder="璇烽�夋嫨鐢熸垚妯″紡" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.AI_GENERATE_MODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="鏄惁鍙戝竷" prop="publicStatus"> - <el-select - v-model="queryParams.publicStatus" - placeholder="璇烽�夋嫨鏄惁鍙戝竷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" width="180" fixed="left" /> - <el-table-column label="闊充箰鍚嶇О" align="center" prop="title" width="180px" fixed="left" /> - <el-table-column label="鐢ㄦ埛" align="center" prop="userId" width="180"> - <template #default="scope"> - <span>{{ userList.find((item) => item.id === scope.row.userId)?.nickname }}</span> - </template> - </el-table-column> - <el-table-column label="闊充箰鐘舵��" align="center" prop="status" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_MUSIC_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="妯″瀷" align="center" prop="model" width="180" /> - <el-table-column label="鍐呭" align="center" width="180"> - <template #default="{ row }"> - <el-link - v-if="row.audioUrl?.length > 0" - type="primary" - :href="row.audioUrl" - target="_blank" - > - 闊充箰 - </el-link> - <el-link - v-if="row.videoUrl?.length > 0" - type="primary" - :href="row.videoUrl" - target="_blank" - class="!pl-5px" - > - 瑙嗛 - </el-link> - <el-link - v-if="row.imageUrl?.length > 0" - type="primary" - :href="row.imageUrl" - target="_blank" - class="!pl-5px" - > - 灏侀潰 - </el-link> - </template> - </el-table-column> - <el-table-column label="鏃堕暱锛堢锛�" align="center" prop="duration" width="100" /> - <el-table-column label="鎻愮ず璇�" align="center" prop="prompt" width="180" /> - <el-table-column label="姝岃瘝" align="center" prop="lyric" width="180" /> - <el-table-column label="鎻忚堪" align="center" prop="gptDescriptionPrompt" width="180" /> - <el-table-column label="鐢熸垚妯″紡" align="center" prop="generateMode" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_GENERATE_MODE" :value="scope.row.generateMode" /> - </template> - </el-table-column> - <el-table-column label="椋庢牸鏍囩" align="center" prop="tags" width="180"> - <template #default="scope"> - <el-tag v-for="tag in scope.row.tags" :key="tag" round class="ml-2px"> - {{ tag }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鏄惁鍙戝竷" align="center" prop="publicStatus"> - <template #default="scope"> - <el-switch - v-model="scope.row.publicStatus" - :active-value="true" - :inactive-value="false" - @change="handleUpdatePublicStatusChange(scope.row)" - :disabled="scope.row.status !== AiMusicStatusEnum.SUCCESS" - /> - </template> - </el-table-column> - <el-table-column label="浠诲姟缂栧彿" align="center" prop="taskId" width="180" /> - <el-table-column label="閿欒淇℃伅" align="center" prop="errorMessage" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="100" fixed="right"> - <template #default="scope"> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:music:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { MusicApi, MusicVO } from '@/api/ai/music' -import * as UserApi from '@/api/system/user' -import { AiMusicStatusEnum } from '@/views/ai/utils/constants' - -/** AI 闊充箰 鍒楄〃 */ -defineOptions({ name: 'AiMusicManager' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<MusicVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: undefined, - title: undefined, - status: undefined, - generateMode: undefined, - createTime: [], - publicStatus: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await MusicApi.getMusicPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await MusicApi.deleteMusic(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 淇敼鏄惁鍙戝竷 */ -const handleUpdatePublicStatusChange = async (row: MusicVO) => { - try { - // 淇敼鐘舵�佺殑浜屾纭 - const text = row.publicStatus ? '鍏紑' : '绉佹湁' - await message.confirm('纭瑕�"' + text + '"璇ラ煶涔愬悧?') - // 鍙戣捣淇敼鐘舵�� - await MusicApi.updateMusic({ - id: row.id, - publicStatus: row.publicStatus - }) - await getList() - } catch { - row.publicStatus = !row.publicStatus - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/ai/utils/constants.ts b/src/views/ai/utils/constants.ts deleted file mode 100644 index 4fee2dc..0000000 --- a/src/views/ai/utils/constants.ts +++ /dev/null @@ -1,416 +0,0 @@ -/** - * Created by 鑺嬮亾婧愮爜 - * - * AI 鏋氫妇绫� - * - * 闂锛氫负浠�涔堜笉鏀惧湪 src/utils/constants.ts 鍛紵 - * 鍥炵瓟锛氫富瑕� AI 鏄彲閫夋ā鍧楋紝鑰冭檻鍒扮嫭绔嬨�佽В鑰︼紝鎵�浠ユ斁鍦ㄤ簡 /views/ai/utils/constants.ts - */ - -/** - * AI 骞冲彴鐨勬灇涓� - */ -export const AiPlatformEnum = { - TONG_YI: 'TongYi', // 闃块噷 - YI_YAN: 'YiYan', // 鐧惧害 - DEEP_SEEK: 'DeepSeek', // DeepSeek - ZHI_PU: 'ZhiPu', // 鏅鸿氨 AI - XING_HUO: 'XingHuo', // 璁 - OPENAI: 'OpenAI', - Ollama: 'Ollama', - STABLE_DIFFUSION: 'StableDiffusion', // Stability AI - MIDJOURNEY: 'Midjourney', // Midjourney - SUNO: 'Suno' // Suno AI -} - -export const OtherPlatformEnum: ImageModelVO[] = [ - { - key: AiPlatformEnum.TONG_YI, - name: '閫氫箟涓囩浉' - }, - { - key: AiPlatformEnum.YI_YAN, - name: '鐧惧害鍗冨竼' - }, - { - key: AiPlatformEnum.ZHI_PU, - name: '鏅鸿氨 AI' - } -] - -/** - * AI 鍥惧儚鐢熸垚鐘舵�佺殑鏋氫妇 - */ -export const AiImageStatusEnum = { - IN_PROGRESS: 10, // 杩涜涓� - SUCCESS: 20, // 宸插畬鎴� - FAIL: 30 // 宸插け璐� -} - -/** - * AI 闊充箰鐢熸垚鐘舵�佺殑鏋氫妇 - */ -export const AiMusicStatusEnum = { - IN_PROGRESS: 10, // 杩涜涓� - SUCCESS: 20, // 宸插畬鎴� - FAIL: 30 // 宸插け璐� -} - -/** - * AI 鍐欎綔绫诲瀷鐨勬灇涓� - */ -export enum AiWriteTypeEnum { - WRITING = 1, // 鎾板啓 - REPLY // 鍥炲 -} - -// 琛ㄦ牸灞曠ず瀵圭収map -export const AiWriteTypeTableRender = { - [AiWriteTypeEnum.WRITING]: '鎾板啓', - [AiWriteTypeEnum.REPLY]: '鍥炲', -} - -// ========== 銆愬浘鐗� UI銆戠浉鍏崇殑鏋氫妇 ========== -export const ImageHotWords = [ - '涓浗鏃楄', - '鍙よ缇庡コ', - '鍗¢�氬ご鍍�', - '鏈虹敳鎴樺+', - '绔ヨ瘽灏忓眿', - '涓浗闀垮煄' -] // 鍥剧墖鐑瘝 - -export const ImageHotEnglishWords = [ - 'Chinese Cheongsam', - 'Ancient Beauty', - 'Cartoon Avatar', - 'Mech Warrior', - 'Fairy Tale Cottage', - 'The Great Wall of China' -] // 鍥剧墖鐑瘝锛堣嫳鏂囷級 - -export interface ImageModelVO { - key: string - name: string - image?: string -} - -export const StableDiffusionSamplers: ImageModelVO[] = [ - { - key: 'DDIM', - name: 'DDIM' - }, - { - key: 'DDPM', - name: 'DDPM' - }, - { - key: 'K_DPMPP_2M', - name: 'K_DPMPP_2M' - }, - { - key: 'K_DPMPP_2S_ANCESTRAL', - name: 'K_DPMPP_2S_ANCESTRAL' - }, - { - key: 'K_DPM_2', - name: 'K_DPM_2' - }, - { - key: 'K_DPM_2_ANCESTRAL', - name: 'K_DPM_2_ANCESTRAL' - }, - { - key: 'K_EULER', - name: 'K_EULER' - }, - { - key: 'K_EULER_ANCESTRAL', - name: 'K_EULER_ANCESTRAL' - }, - { - key: 'K_HEUN', - name: 'K_HEUN' - }, - { - key: 'K_LMS', - name: 'K_LMS' - } -] - -export const StableDiffusionStylePresets: ImageModelVO[] = [ - { - key: '3d-model', - name: '3d-model' - }, - { - key: 'analog-film', - name: 'analog-film' - }, - { - key: 'anime', - name: 'anime' - }, - { - key: 'cinematic', - name: 'cinematic' - }, - { - key: 'comic-book', - name: 'comic-book' - }, - { - key: 'digital-art', - name: 'digital-art' - }, - { - key: 'enhance', - name: 'enhance' - }, - { - key: 'fantasy-art', - name: 'fantasy-art' - }, - { - key: 'isometric', - name: 'isometric' - }, - { - key: 'line-art', - name: 'line-art' - }, - { - key: 'low-poly', - name: 'low-poly' - }, - { - key: 'modeling-compound', - name: 'modeling-compound' - }, - // neon-punk origami photographic pixel-art tile-texture - { - key: 'neon-punk', - name: 'neon-punk' - }, - { - key: 'origami', - name: 'origami' - }, - { - key: 'photographic', - name: 'photographic' - }, - { - key: 'pixel-art', - name: 'pixel-art' - }, - { - key: 'tile-texture', - name: 'tile-texture' - } -] - -export const TongYiWanXiangModels: ImageModelVO[] = [ - { - key: 'wanx-v1', - name: 'wanx-v1' - }, - { - key: 'wanx-sketch-to-image-v1', - name: 'wanx-sketch-to-image-v1' - } -] - -export const QianFanModels: ImageModelVO[] = [ - { - key: 'sd_xl', - name: 'sd_xl' - } -] - -export const ChatGlmModels: ImageModelVO[] = [ - { - key: 'cogview-3', - name: 'cogview-3' - } -] - -export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [ - { - key: 'NONE', - name: 'NONE' - }, - { - key: 'FAST_BLUE', - name: 'FAST_BLUE' - }, - { - key: 'FAST_GREEN', - name: 'FAST_GREEN' - }, - { - key: 'SIMPLE', - name: 'SIMPLE' - }, - { - key: 'SLOW', - name: 'SLOW' - }, - { - key: 'SLOWER', - name: 'SLOWER' - }, - { - key: 'SLOWEST', - name: 'SLOWEST' - } -] - -export const Dall3Models: ImageModelVO[] = [ - { - key: 'dall-e-3', - name: 'DALL路E 3', - image: `/src/assets/ai/dall2.jpg` - }, - { - key: 'dall-e-2', - name: 'DALL路E 2', - image: `/src/assets/ai/dall3.jpg` - } -] - -export const Dall3StyleList: ImageModelVO[] = [ - { - key: 'vivid', - name: '娓呮櫚', - image: `/src/assets/ai/qingxi.jpg` - }, - { - key: 'natural', - name: '鑷劧', - image: `/src/assets/ai/ziran.jpg` - } -] - -export interface ImageSizeVO { - key: string - name?: string - style: string - width: string - height: string -} - -export const Dall3SizeList: ImageSizeVO[] = [ - { - key: '1024x1024', - name: '1:1', - width: '1024', - height: '1024', - style: 'width: 30px; height: 30px;background-color: #dcdcdc;' - }, - { - key: '1024x1792', - name: '3:5', - width: '1024', - height: '1792', - style: 'width: 30px; height: 50px;background-color: #dcdcdc;' - }, - { - key: '1792x1024', - name: '5:3', - width: '1792', - height: '1024', - style: 'width: 50px; height: 30px;background-color: #dcdcdc;' - } -] - -export const MidjourneyModels: ImageModelVO[] = [ - { - key: 'midjourney', - name: 'MJ', - image: 'https://bigpt8.com/pc/_nuxt/mj.34a61377.png' - }, - { - key: 'niji', - name: 'NIJI', - image: 'https://bigpt8.com/pc/_nuxt/nj.ca79b143.png' - } -] - -export const MidjourneySizeList: ImageSizeVO[] = [ - { - key: '1:1', - width: '1', - height: '1', - style: 'width: 30px; height: 30px;background-color: #dcdcdc;' - }, - { - key: '3:4', - width: '3', - height: '4', - style: 'width: 30px; height: 40px;background-color: #dcdcdc;' - }, - { - key: '4:3', - width: '4', - height: '3', - style: 'width: 40px; height: 30px;background-color: #dcdcdc;' - }, - { - key: '9:16', - width: '9', - height: '16', - style: 'width: 30px; height: 50px;background-color: #dcdcdc;' - }, - { - key: '16:9', - width: '16', - height: '9', - style: 'width: 50px; height: 30px;background-color: #dcdcdc;' - } -] - -export const MidjourneyVersions = [ - { - value: '6.0', - label: 'v6.0' - }, - { - value: '5.2', - label: 'v5.2' - }, - { - value: '5.1', - label: 'v5.1' - }, - { - value: '5.0', - label: 'v5.0' - }, - { - value: '4.0', - label: 'v4.0' - } -] - -export const NijiVersionList = [ - { - value: '5', - label: 'v5' - } -] - -// ========== 銆愬啓浣� UI銆戠浉鍏崇殑鏋氫妇 ========== - -/** 鍐欎綔鐐瑰嚮绀轰緥鏃剁殑鏁版嵁 **/ -export const WriteExample = { - write: { - prompt: 'vue', - data: 'Vue.js 鏄竴绉嶇敤浜庢瀯寤虹敤鎴风晫闈㈢殑娓愯繘寮� JavaScript 妗嗘灦銆傚畠鐨勬牳蹇冨簱鍙叧娉ㄨ鍥惧眰锛屾槗浜庝笂鎵嬶紝鍚屾椂涔熶究浜庝笌鍏朵粬搴撴垨宸叉湁椤圭洰鏁村悎銆俓n\nVue.js 鐨勭壒鐐瑰寘鎷細\n- 鍝嶅簲寮忕殑鏁版嵁缁戝畾锛歏ue.js 浼氳嚜鍔ㄥ皢鏁版嵁涓� DOM 鍚屾锛屼娇寰楃姸鎬佺鐞嗗彉寰楁洿鍔犵畝鍗曘�俓n- 缁勪欢鍖栵細Vue.js 鍏佽寮�鍙戣�呴�氳繃灏忓瀷銆佺嫭绔嬪拰閫氬父鍙鐢ㄧ殑缁勪欢鏋勫缓澶у瀷搴旂敤銆俓n- 铏氭嫙 DOM锛歏ue.js 浣跨敤铏氭嫙 DOM 瀹炵幇蹇�熸覆鏌擄紝鎻愰珮浜嗘�ц兘銆俓n\n鍦� Vue.js 涓紝涓�涓吀鍨嬬殑搴旂敤缁撴瀯鍙兘鍖呮嫭锛歕n1. 鏍瑰疄渚嬶細姣忎釜 Vue 搴旂敤閮介渶瑕佷竴涓牴瀹炰緥浣滀负鍏ュ彛鐐广�俓n2. 缁勪欢绯荤粺锛氬彲浠ュ垱寤鸿嚜瀹氫箟鐨勫彲澶嶇敤缁勪欢銆俓n3. 鎸囦护锛氱壒娈婄殑甯︽湁鍓嶇紑 v- 鐨勫睘鎬э紝涓� DOM 鍏冪礌鎻愪緵鐗规畩鐨勮涓恒�俓n4. 鎻掑�硷細鐢ㄤ簬鏂囨湰鍐呭锛屽皢鏁版嵁鍔ㄦ�佸湴鎻掑叆鍒� HTML銆俓n5. 璁$畻灞炴�у拰渚﹀惉鍣細鐢ㄤ簬澶勭悊鏁版嵁鐨勫鏉傞�昏緫鍜屽搷搴旀暟鎹彉鍖栥�俓n6. 鏉′欢娓叉煋锛氭牴鎹潯浠跺喅瀹氬厓绱犵殑娓叉煋銆俓n7. 鍒楄〃娓叉煋锛氱敤浜庢樉绀哄垪琛ㄦ暟鎹�俓n8. 浜嬩欢澶勭悊锛氬搷搴旂敤鎴蜂氦浜掋�俓n9. 琛ㄥ崟杈撳叆缁戝畾锛氬鐞嗚〃鍗曡緭鍏ュ拰楠岃瘉銆俓n10. 缁勪欢鐢熷懡鍛ㄦ湡閽╁瓙锛氬湪缁勪欢鐨勪笉鍚岄樁娈垫墽琛岀壒瀹氱殑鍑芥暟銆俓n\nVue.js 杩樻彁渚涗簡瀹樻柟鐨勮矾鐢卞櫒 Vue Router 鍜岀姸鎬佺鐞嗗簱 Vuex锛屼互鏀寔鏋勫缓澶嶆潅鐨勫崟椤靛簲鐢紙SPA锛夈�俓n\n鍦ㄥ紑鍙戣繃绋嬩腑锛屽紑鍙戣�呴�氬父浼氫娇鐢� Vue CLI锛岃繖鏄竴涓己澶х殑鍛戒护琛屽伐鍏凤紝鐢ㄤ簬蹇�熺敓鎴� Vue 椤圭洰鑴氭墜鏋讹紝闆嗘垚浜嗚濡� Babel銆乄ebpack 绛夌幇浠e墠绔伐鍏凤紝浠ュ強鐑噸杞姐�佷唬鐮佹娴嬬瓑寮�鍙戜綋楠屼紭鍖栧姛鑳姐�俓n\nVue.js 鐨勭敓鎬佺郴缁熻繕鍖呮嫭澶ч噺鐨勭涓夋柟搴撳拰鎻掍欢锛屽 Vuetify锛圲I 缁勪欢搴擄級銆乂ue Test Utils锛堟祴璇曞伐鍏凤級绛夛紝杩欎簺閮芥瀬澶у湴涓板瘜浜� Vue.js 鐨勫紑鍙戠敓鎬併�俓n\n鎬荤殑鏉ヨ锛孷ue.js 鏄竴涓伒娲汇�侀珮鏁堢殑鍓嶇妗嗘灦锛岄�傚悎浠庡皬鍨嬮」鐩埌澶у瀷浼佷笟绾у簲鐢ㄧ殑寮�鍙戙�傚畠鐨勬槗鐢ㄦ�с�佺伒娲绘�у拰寮哄ぇ鐨勭ぞ鍖烘敮鎸佷娇鍏舵垚涓鸿澶氬紑鍙戣�呯殑棣栭�夋鏋朵箣涓�銆�' - }, - reply: { - originalContent: '棰嗗锛屾垜鎯宠鍋�', - prompt: '涓嶆壒', - data: '鎮ㄧ殑璇峰亣鐢宠宸叉敹鎮夛紝缁忔牳瀹炲拰鑰冭檻锛屾殏鏃舵棤娉曟壒鍑嗘偍鐨勮鍋囩敵璇枫�俓n\n濡傛湁鐗规畩鎯呭喌鎴栫揣鎬ヤ簨鍔★紝璇峰強鏃朵笌鎴戣仈绯汇�俓n\n绁濆伐浣滈『鍒┿�俓n\n璋㈣阿銆�' - } -} diff --git a/src/views/ai/utils/utils.ts b/src/views/ai/utils/utils.ts deleted file mode 100644 index ab45ae1..0000000 --- a/src/views/ai/utils/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Created by 鑺嬮亾婧愮爜 - * - * AI 鏋氫妇绫� - * - * 闂锛氫负浠�涔堜笉鏀惧湪 src/utils/common-utils.ts 鍛紵 - * 鍥炵瓟锛氫富瑕� AI 鏄彲閫夋ā鍧楋紝鑰冭檻鍒扮嫭绔嬨�佽В鑰︼紝鎵�浠ユ斁鍦ㄤ簡 /views/ai/utils/common-utils.ts - */ - -/** 鍒ゆ柇瀛楃涓叉槸鍚﹀寘鍚腑鏂� */ -export const hasChinese = (str: string) => { - return /[\u4e00-\u9fa5]/.test(str) -} diff --git a/src/views/ai/write/index/components/Left.vue b/src/views/ai/write/index/components/Left.vue deleted file mode 100644 index 05cc04a..0000000 --- a/src/views/ai/write/index/components/Left.vue +++ /dev/null @@ -1,213 +0,0 @@ -<template> - <!-- 瀹氫箟 tab 缁勪欢锛氭挵鍐�/鍥炲绛� --> - <DefineTab v-slot="{ active, text, itemClick }"> - <span - class="inline-block w-1/2 rounded-full cursor-pointer text-center leading-[30px] relative z-1 text-[5C6370] hover:text-black" - :class="active ? 'text-black shadow-md' : 'hover:bg-[#DDDFE3]'" - @click="itemClick" - > - {{ text }} - </span> - </DefineTab> - <!-- 瀹氫箟 label 缁勪欢锛氶暱搴�/鏍煎紡/璇皵/璇█绛� --> - <DefineLabel v-slot="{ label, hint, hintClick }"> - <h3 class="mt-5 mb-3 flex items-center justify-between text-[14px]"> - <span>{{ label }}</span> - <span - @click="hintClick" - v-if="hint" - class="flex items-center text-[12px] text-[#846af7] cursor-pointer select-none" - > - <Icon icon="ep:question-filled" /> - {{ hint }} - </span> - </h3> - </DefineLabel> - - <div class="flex flex-col" v-bind="$attrs"> - <!-- tab --> - <div class="w-full pt-2 bg-[#f5f7f9] flex justify-center"> - <div class="w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"> - <div - class="flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full" - :class=" - selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]' - " - > - <ReuseTab - v-for="tab in tabs" - :key="tab.value" - :text="tab.text" - :active="tab.value === selectedTab" - :itemClick="() => switchTab(tab.value)" - /> - </div> - </div> - </div> - <div - class="px-7 pb-2 flex-grow overflow-y-auto lg:block w-[380px] box-border bg-[#f5f7f9] h-full" - > - <div> - <template v-if="selectedTab === 1"> - <ReuseLabel label="鍐欎綔鍐呭" hint="绀轰緥" :hint-click="() => example('write')" /> - <el-input - type="textarea" - :rows="5" - :maxlength="500" - v-model="formData.prompt" - placeholder="璇疯緭鍏ュ啓浣滃唴瀹�" - showWordLimit - /> - </template> - - <template v-else> - <ReuseLabel label="鍘熸枃" hint="绀轰緥" :hint-click="() => example('reply')" /> - <el-input - type="textarea" - :rows="5" - :maxlength="500" - v-model="formData.originalContent" - placeholder="璇疯緭鍏ュ師鏂�" - showWordLimit - /> - - <ReuseLabel label="鍥炲鍐呭" /> - <el-input - type="textarea" - :rows="5" - :maxlength="500" - v-model="formData.prompt" - placeholder="璇疯緭鍏ュ洖澶嶅唴瀹�" - showWordLimit - /> - </template> - - <ReuseLabel label="闀垮害" /> - <Tag v-model="formData.length" :tags="getIntDictOptions(DICT_TYPE.AI_WRITE_LENGTH)" /> - <ReuseLabel label="鏍煎紡" /> - <Tag v-model="formData.format" :tags="getIntDictOptions(DICT_TYPE.AI_WRITE_FORMAT)" /> - <ReuseLabel label="璇皵" /> - <Tag v-model="formData.tone" :tags="getIntDictOptions(DICT_TYPE.AI_WRITE_TONE)" /> - <ReuseLabel label="璇█" /> - <Tag v-model="formData.language" :tags="getIntDictOptions(DICT_TYPE.AI_WRITE_LANGUAGE)" /> - - <div class="flex items-center justify-center mt-3"> - <el-button :disabled="isWriting" @click="reset">閲嶇疆</el-button> - <el-button :loading="isWriting" @click="submit" color="#846af7">鐢熸垚</el-button> - </div> - </div> - </div> - </div> -</template> - -<script setup lang="ts"> -import { createReusableTemplate } from '@vueuse/core' -import { ref } from 'vue' -import Tag from './Tag.vue' -import { WriteVO } from 'src/api/ai/write' -import { omit } from 'lodash-es' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { AiWriteTypeEnum, WriteExample } from '@/views/ai/utils/constants' - -type TabType = WriteVO['type'] - -const message = useMessage() // 娑堟伅寮圭獥 - -defineProps<{ - isWriting: boolean -}>() - -const emits = defineEmits<{ - (e: 'submit', params: Partial<WriteVO>) - (e: 'example', param: 'write' | 'reply') - (e: 'reset') -}>() - -/** 鐐瑰嚮绀轰緥鐨勬椂鍊欙紝灏嗗畾涔夊ソ鐨勬枃绔犱綔涓虹ず渚嬪睍绀哄嚭鏉� **/ -const example = (type: 'write' | 'reply') => { - formData.value = { - ...initData, - ...omit(WriteExample[type], ['data']) - } - emits('example', type) -} - -/** 閲嶇疆锛屽皢琛ㄥ崟鍊间綔涓哄垵閫夊�� **/ -const reset = () => { - formData.value = { ...initData } - emits('reset') -} - -const selectedTab = ref<TabType>(AiWriteTypeEnum.WRITING) -const tabs: { - text: string - value: TabType -}[] = [ - { text: '鎾板啓', value: AiWriteTypeEnum.WRITING }, - { text: '鍥炲', value: AiWriteTypeEnum.REPLY } -] -const [DefineTab, ReuseTab] = createReusableTemplate<{ - active?: boolean - text: string - itemClick: () => void -}>() - -/** - * 鍙互鍦� template 閲岃竟瀹氫箟鍙鐢ㄧ殑缁勪欢锛孌efineLabel锛孯euseLabel 鏄噰鐢ㄧ殑瑙f瀯璧嬪�硷紝閮芥槸 Vue 缁勪欢 - * - * 鐩存帴閫氳繃缁勪欢鐨勫舰寮忎娇鐢紝<DefineLabel v-slot="{ label, hint, hintClick }"> 涓棿鏄渶瑕佸鐢ㄧ殑缁勪欢浠g爜 <DefineLabel />锛岄�氳繃 <ReuseLabel /> 鏉ヤ娇鐢ㄥ畾涔夌殑缁勪欢 - * DefineLabel 閲岃竟鐨� v-slot="{ label, hint, hintClick }"鐩稿綋浜庢槸瑙f瀯浜嗙粍浠剁殑 prop锛岄渶瑕佹敞鎰忕殑鏄� boolean 绫诲瀷锛岄渶瑕佹樉寮忕殑璧嬪�兼瘮濡� <ReuseLabel :flag="true" /> - * 浜嬩欢涔熷緱浠� prop 褰㈠紡浼犲叆锛屼笉鑳芥槸 @event鐨勫舰寮忥紝姣斿涓嬮潰鐨� hintClick 闇�瑕�<ReuseLabel :hintClick="() => { doSomething }"/> - * - * @see https://vueuse.org/createReusableTemplate - */ -const [DefineLabel, ReuseLabel] = createReusableTemplate<{ - label: string - class?: string - hint?: string - hintClick?: () => void -}>() - -const initData: WriteVO = { - type: 1, - prompt: '', - originalContent: '', - tone: 1, - language: 1, - length: 1, - format: 1 -} -const formData = ref<WriteVO>({ ...initData }) - -/** 鐢ㄦ潵璁板綍鍒囨崲涔嬪墠鎵�濉啓鐨勬暟鎹紝鍒囨崲鐨勬椂鍊欑粰璧嬪�煎洖鏉� **/ -const recordFormData = {} as Record<AiWriteTypeEnum, WriteVO> - -/** 鍒囨崲tab **/ -const switchTab = (value: TabType) => { - if (value !== selectedTab.value) { - // 淇濆瓨涔嬪墠鐨勪箙鏁版嵁 - recordFormData[selectedTab.value] = formData.value - selectedTab.value = value - // 灏嗕箣鍓嶇殑鏃ф暟鎹祴鍊煎洖鏉� - formData.value = { ...initData, ...recordFormData[value] } - } -} - -/** 鎻愪氦鍐欎綔 */ -const submit = () => { - if (selectedTab.value === 2 && !formData.value.originalContent) { - message.warning('璇疯緭鍏ュ師鏂�') - return - } - if (!formData.value.prompt) { - message.warning(`璇疯緭鍏�${selectedTab.value === 1 ? '鍐欎綔' : '鍥炲'}鍐呭`) - return - } - emits('submit', { - /** 鎾板啓鐨勬椂鍊欐病鏈� originalContent 瀛楁**/ - ...(selectedTab.value === 1 ? omit(formData.value, ['originalContent']) : formData.value), - /** 浣跨敤閫変腑 tab 鍊艰鐩栧綋鍓嶇殑 type 绫诲瀷 **/ - type: selectedTab.value - }) -} -</script> diff --git a/src/views/ai/write/index/components/Right.vue b/src/views/ai/write/index/components/Right.vue deleted file mode 100644 index d0aada5..0000000 --- a/src/views/ai/write/index/components/Right.vue +++ /dev/null @@ -1,120 +0,0 @@ -<template> - <el-card class="my-card h-full"> - <template #header> - <h3 class="m-0 px-7 shrink-0 flex items-center justify-between"> - <span>棰勮</span> - <!-- 灞曠ず鍦ㄥ彸涓婅 --> - <el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small"> - <template #icon> - <Icon icon="ph:copy-bold" /> - </template> - 澶嶅埗 - </el-button> - </h3> - </template> - - <div ref="contentRef" class="hide-scroll-bar h-full box-border overflow-y-auto"> - <div class="w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7"> - <!-- 缁堟鐢熸垚鍐呭鐨勬寜閽� --> - <el-button - v-show="isWriting" - class="absolute bottom-2 sm:bottom-5 left-1/2 -translate-x-1/2 z-36" - @click="emits('stopStream')" - size="small" - > - <template #icon> - <Icon icon="material-symbols:stop" /> - </template> - 缁堟鐢熸垚 - </el-button> - <el-input - id="inputId" - type="textarea" - v-model="compContent" - autosize - :input-style="{ boxShadow: 'none' }" - resize="none" - placeholder="鐢熸垚鐨勫唴瀹光�︹��" - /> - </div> - </div> - </el-card> -</template> - -<script setup lang="ts"> -import { useClipboard } from '@vueuse/core' - -const message = useMessage() // 娑堟伅寮圭獥 -const { copied, copy } = useClipboard() // 绮樿创鏉� - -const props = defineProps({ - content: { - // 鐢熸垚鐨勭粨鏋� - type: String, - default: '' - }, - isWriting: { - // 鏄惁姝e湪鐢熸垚鏂囩珷 - type: Boolean, - default: false - } -}) - -const emits = defineEmits(['update:content', 'stopStream']) - -/** 閫氳繃璁$畻灞炴�э紝鍙屽悜缁戝畾锛屾洿鏀圭敓鎴愮殑鍐呭锛岃�冭檻鍒扮敤鎴锋兂瑕佹洿鏀圭敓鎴愭枃绔犵殑鎯呭喌 */ -const compContent = computed({ - get() { - return props.content - }, - set(val) { - emits('update:content', val) - } -}) - -/** 婊氬姩 */ -const contentRef = ref<HTMLDivElement>() -defineExpose({ - scrollToBottom() { - contentRef.value?.scrollTo(0, contentRef.value?.scrollHeight) - } -}) - -/** 鐐瑰嚮澶嶅埗鐨勬椂鍊欏鍒跺唴瀹� */ -const showCopy = computed(() => props.content && !props.isWriting) // 鏄惁灞曠ず澶嶅埗鎸夐挳锛屽湪鐢熸垚鍐呭瀹屾垚鐨勬椂鍊欏睍绀� -const copyContent = () => { - copy(props.content) -} - -/** 澶嶅埗鎴愬姛鐨勬椂鍊� copied.value 涓� true */ -watch(copied, (val) => { - if (val) { - message.success('澶嶅埗鎴愬姛') - } -}) -</script> - -<style lang="scss" scoped> -.hide-scroll-bar { - -ms-overflow-style: none; - scrollbar-width: none; - - &::-webkit-scrollbar { - width: 0; - height: 0; - } -} - -.my-card { - display: flex; - flex-direction: column; - - :deep(.el-card__body) { - box-sizing: border-box; - flex-grow: 1; - overflow-y: auto; - padding: 0; - @extend .hide-scroll-bar; - } -} -</style> diff --git a/src/views/ai/write/index/components/Tag.vue b/src/views/ai/write/index/components/Tag.vue deleted file mode 100644 index 3d616be..0000000 --- a/src/views/ai/write/index/components/Tag.vue +++ /dev/null @@ -1,32 +0,0 @@ -<!-- 鏍囩閫夐」 --> -<template> - <div class="flex flex-wrap gap-[8px]"> - <span - v-for="tag in props.tags" - :key="tag.value" - class="tag mb-2 border-[2px] border-solid border-[#DDDFE3] px-2 leading-6 text-[12px] bg-[#DDDFE3] rounded-[4px] cursor-pointer" - :class="modelValue === tag.value && '!border-[#846af7] text-[#846af7]'" - @click="emits('update:modelValue', tag.value)" - > - {{ tag.label }} - </span> - </div> -</template> - -<script setup lang="ts"> -const props = withDefaults( - defineProps<{ - tags: { label: string; value: string }[] - modelValue: string - [k: string]: any - }>(), - { - tags: () => [] - } -) - -const emits = defineEmits<{ - (e: 'update:modelValue', value: string): void -}>() -</script> -<style scoped></style> diff --git a/src/views/ai/write/index/index.vue b/src/views/ai/write/index/index.vue deleted file mode 100644 index 0dfda74..0000000 --- a/src/views/ai/write/index/index.vue +++ /dev/null @@ -1,76 +0,0 @@ -<template> - <div class="absolute top-0 left-0 right-0 bottom-0 flex"> - <Left - :is-writing="isWriting" - class="h-full" - @submit="submit" - @reset="reset" - @example="handleExampleClick" - /> - <Right - :is-writing="isWriting" - @stop-stream="stopStream" - ref="rightRef" - class="flex-grow" - v-model:content="writeResult" - /> - </div> -</template> - -<script setup lang="ts"> -import Left from './components/Left.vue' -import Right from './components/Right.vue' -import { WriteApi, WriteVO } from '@/api/ai/write' -import { WriteExample } from '@/views/ai/utils/constants' - -const message = useMessage() - -const writeResult = ref('') // 鍐欎綔缁撴灉 -const isWriting = ref(false) // 鏄惁姝e湪鍐欎綔涓� -const abortController = ref<AbortController>() // // 鍐欎綔杩涜涓� abort 鎺у埗鍣�(鎺у埗 stream 鍐欎綔) - -/** 鍋滄 stream 鐢熸垚 */ -const stopStream = () => { - abortController.value?.abort() - isWriting.value = false -} - -/** 鎵ц鍐欎綔 */ -const rightRef = ref<InstanceType<typeof Right>>() -const submit = (data: WriteVO) => { - abortController.value = new AbortController() - writeResult.value = '' - isWriting.value = true - WriteApi.writeStream({ - data, - onMessage: async (res) => { - const { code, data, msg } = JSON.parse(res.data) - if (code !== 0) { - message.alert(`鍐欎綔寮傚父! ${msg}`) - stopStream() - return - } - writeResult.value = writeResult.value + data - // 婊氬姩鍒板簳閮� - await nextTick() - rightRef.value?.scrollToBottom() - }, - ctrl: abortController.value, - onClose: stopStream, - onError: (...err) => { - console.error('鍐欎綔寮傚父', ...err) - stopStream() - } - }) -} - -/** 鐐瑰嚮绀轰緥瑙﹀彂 */ -const handleExampleClick = (type: keyof typeof WriteExample) => { - writeResult.value = WriteExample[type].data -} - -/** 鐐瑰嚮閲嶇疆鐨勬椂鍊欐竻绌哄啓浣滅殑缁撴灉**/ -const reset = () => { - writeResult.value = '' -} -</script> diff --git a/src/views/ai/write/manager/index.vue b/src/views/ai/write/manager/index.vue deleted file mode 100644 index ddd1400..0000000 --- a/src/views/ai/write/manager/index.vue +++ /dev/null @@ -1,256 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-select - v-model="queryParams.userId" - clearable - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍐欎綔绫诲瀷" prop="type"> - <el-select - v-model="queryParams.type" - placeholder="璇烽�夋嫨鍐欎綔绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.AI_WRITE_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="骞冲彴" prop="platform"> - <el-select v-model="queryParams.platform" placeholder="璇烽�夋嫨骞冲彴" clearable class="!w-240px"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['ai:write:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <!-- TODO @YunaiV 鐩墠娌℃湁瀵煎嚭鎺ュ彛锛岄渶瑕佸鍑哄悧 --> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['ai:write:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" width="120" fixed="left" /> - <el-table-column label="鐢ㄦ埛" align="center" prop="userId" width="180"> - <template #default="scope"> - <span>{{ userList.find((item) => item.id === scope.row.userId)?.nickname }}</span> - </template> - </el-table-column> - <el-table-column label="鍐欎綔绫诲瀷" align="center" prop="type"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_WRITE_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column label="骞冲彴" align="center" prop="platform" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" /> - </template> - </el-table-column> - <el-table-column label="妯″瀷" align="center" prop="model" width="180" /> - <el-table-column - label="鐢熸垚鍐呭鎻愮ず" - align="center" - prop="prompt" - width="180" - show-overflow-tooltip - /> - <el-table-column label="鐢熸垚鐨勫唴瀹�" align="center" prop="generatedContent" width="180" /> - <el-table-column label="鍘熸枃" align="center" prop="originalContent" width="180" /> - <el-table-column label="闀垮害" align="center" prop="length"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_WRITE_LENGTH" :value="scope.row.length" /> - </template> - </el-table-column> - <el-table-column label="鏍煎紡" align="center" prop="format"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_WRITE_FORMAT" :value="scope.row.format" /> - </template> - </el-table-column> - <el-table-column label="璇皵" align="center" prop="tone"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_WRITE_TONE" :value="scope.row.tone" /> - </template> - </el-table-column> - <el-table-column label="璇█" align="center" prop="language"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.AI_WRITE_LANGUAGE" :value="scope.row.language" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="閿欒淇℃伅" align="center" prop="errorMessage" /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> -<!-- TODO @YunaiV 鐩墠娌℃湁淇敼鎺ュ彛锛屽啓浣滆鍙互鏇存敼鍚�--> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['ai:write:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['ai:write:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { useRouter } from 'vue-router' -import { WriteApi, AiWritePageReqVO, AiWriteRespVo } from '@/api/ai/write' -import * as UserApi from '@/api/system/user' - -/** AI 鍐欎綔鍒楄〃 */ -defineOptions({ name: 'AiWriteManager' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const router = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<AiWriteRespVo[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive<AiWritePageReqVO>({ - pageNo: 1, - pageSize: 10, - userId: undefined, - type: undefined, - platform: undefined, - createTime: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await WriteApi.getWritePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鏂板鏂规硶锛岃烦杞埌鍐欎綔椤甸潰 **/ -const openForm = (type: string, id?: number) => { - switch (type) { - case 'create': - router.push('/ai/write') - break - } -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await WriteApi.deleteWrite(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - getList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/bpm/category/CategoryForm.vue b/src/views/bpm/category/CategoryForm.vue deleted file mode 100644 index 5b77153..0000000 --- a/src/views/bpm/category/CategoryForm.vue +++ /dev/null @@ -1,124 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍒嗙被鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ垎绫诲悕" /> - </el-form-item> - <el-form-item label="鍒嗙被鏍囧織" prop="code"> - <el-input v-model="formData.code" placeholder="璇疯緭鍏ュ垎绫绘爣蹇�" /> - </el-form-item> - <el-form-item label="鍒嗙被鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鍒嗙被鎺掑簭" prop="sort"> - <el-input-number - v-model="formData.sort" - placeholder="璇疯緭鍏ュ垎绫绘帓搴�" - class="!w-1/1" - :precision="0" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { CategoryApi, CategoryVO } from '@/api/bpm/category' - -/** BPM 娴佺▼鍒嗙被 琛ㄥ崟 */ -defineOptions({ name: 'CategoryForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - code: undefined, - status: undefined, - sort: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍒嗙被鍚嶄笉鑳戒负绌�', trigger: 'blur' }], - code: [{ required: true, message: '鍒嗙被鏍囧織涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鍒嗙被鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鍒嗙被鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await CategoryApi.getCategory(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as CategoryVO - if (formType.value === 'create') { - await CategoryApi.createCategory(data) - message.success(t('common.createSuccess')) - } else { - await CategoryApi.updateCategory(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - code: undefined, - status: undefined, - sort: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/category/index.vue b/src/views/bpm/category/index.vue deleted file mode 100644 index 085b371..0000000 --- a/src/views/bpm/category/index.vue +++ /dev/null @@ -1,199 +0,0 @@ -<template> - <doc-alert title="宸ヤ綔娴佹墜鍐�" url="https://doc.iocoder.cn/bpm/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍒嗙被鍚�" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ垎绫诲悕" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒嗙被鏍囧織" prop="code"> - <el-input - v-model="queryParams.code" - placeholder="璇疯緭鍏ュ垎绫绘爣蹇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒嗙被鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨鍒嗙被鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['bpm:category:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍒嗙被缂栧彿" align="center" prop="id" /> - <el-table-column label="鍒嗙被鍚�" align="center" prop="name" /> - <el-table-column label="鍒嗙被鏍囧織" align="center" prop="code" /> - <el-table-column label="鍒嗙被鎻忚堪" align="center" prop="description" /> - <el-table-column label="鍒嗙被鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鍒嗙被鎺掑簭" align="center" prop="sort" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['bpm:category:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['bpm:category:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CategoryForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { CategoryApi, CategoryVO } from '@/api/bpm/category' -import CategoryForm from './CategoryForm.vue' - -/** BPM 娴佺▼鍒嗙被 鍒楄〃 */ -defineOptions({ name: 'BpmCategory' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<CategoryVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - code: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CategoryApi.getCategoryPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await CategoryApi.deleteCategory(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/definition/index.vue b/src/views/bpm/definition/index.vue deleted file mode 100644 index 1e7794b..0000000 --- a/src/views/bpm/definition/index.vue +++ /dev/null @@ -1,149 +0,0 @@ -<template> - <doc-alert title="宸ヤ綔娴佹墜鍐�" url="https://doc.iocoder.cn/bpm/" /> - - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="瀹氫箟缂栧彿" align="center" prop="id" width="400" /> - <el-table-column label="娴佺▼鍚嶇О" align="center" prop="name" width="200"> - <template #default="scope"> - <el-button type="primary" link @click="handleBpmnDetail(scope.row)"> - <span>{{ scope.row.name }}</span> - </el-button> - </template> - </el-table-column> - <el-table-column label="瀹氫箟鍒嗙被" align="center" prop="categoryName" width="100" /> - <el-table-column label="琛ㄥ崟淇℃伅" align="center" prop="formType" width="200"> - <template #default="scope"> - <el-button - v-if="scope.row.formType === 10" - type="primary" - link - @click="handleFormDetail(scope.row)" - > - <span>{{ scope.row.formName }}</span> - </el-button> - <el-button v-else type="primary" link @click="handleFormDetail(scope.row)"> - <span>{{ scope.row.formCustomCreatePath }}</span> - </el-button> - </template> - </el-table-column> - <el-table-column label="娴佺▼鐗堟湰" align="center" prop="processDefinition.version" width="80"> - <template #default="scope"> - <el-tag v-if="scope.row">v{{ scope.row.version }}</el-tag> - <el-tag type="warning" v-else>鏈儴缃�</el-tag> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="version" width="80"> - <template #default="scope"> - <el-tag type="success" v-if="scope.row.suspensionState === 1">婵�娲�</el-tag> - <el-tag type="warning" v-if="scope.row.suspensionState === 2">鎸傝捣</el-tag> - </template> - </el-table-column> - <el-table-column - label="閮ㄧ讲鏃堕棿" - align="center" - prop="deploymentTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column - label="瀹氫箟鎻忚堪" - align="center" - prop="description" - width="300" - show-overflow-tooltip - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 寮圭獥锛氳〃鍗曡鎯� --> - <Dialog title="琛ㄥ崟璇︽儏" v-model="formDetailVisible" width="800"> - <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" /> - </Dialog> - - <!-- 寮圭獥锛氭祦绋嬫ā鍨嬪浘鐨勯瑙� --> - <Dialog title="娴佺▼鍥�" v-model="bpmnDetailVisible" width="800"> - <MyProcessViewer - key="designer" - v-model="bpmnXml" - :value="bpmnXml as any" - v-bind="bpmnControlForm" - :prefix="bpmnControlForm.prefix" - /> - </Dialog> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import { MyProcessViewer } from '@/components/bpmnProcessDesigner/package' -import * as DefinitionApi from '@/api/bpm/definition' -import { setConfAndFields2 } from '@/utils/formCreate' - -defineOptions({ name: 'BpmProcessDefinition' }) - -const { push } = useRouter() // 璺敱 -const { query } = useRoute() // 鏌ヨ鍙傛暟 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - key: query.key -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DefinitionApi.getProcessDefinitionPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 娴佺▼琛ㄥ崟鐨勮鎯呮寜閽搷浣� */ -const formDetailVisible = ref(false) -const formDetailPreview = ref({ - rule: [], - option: {} -}) -const handleFormDetail = async (row) => { - if (row.formType == 10) { - // 璁剧疆琛ㄥ崟 - setConfAndFields2(formDetailPreview, row.formConf, row.formFields) - // 寮圭獥鎵撳紑 - formDetailVisible.value = true - } else { - await push({ - path: row.formCustomCreatePath - }) - } -} - -/** 娴佺▼鍥剧殑璇︽儏鎸夐挳鎿嶄綔 */ -const bpmnDetailVisible = ref(false) -const bpmnXml = ref(null) -const bpmnControlForm = ref({ - prefix: 'flowable' -}) -const handleBpmnDetail = async (row) => { - bpmnXml.value = (await DefinitionApi.getProcessDefinition(row.id))?.bpmnXml - bpmnDetailVisible.value = true -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/form/editor/index.vue b/src/views/bpm/form/editor/index.vue deleted file mode 100644 index 0d1230c..0000000 --- a/src/views/bpm/form/editor/index.vue +++ /dev/null @@ -1,121 +0,0 @@ -<template> - <ContentWrap> - <!-- 琛ㄥ崟璁捐鍣� --> - <FcDesigner ref="designer" height="780px"> - <template #handle> - <el-button round size="small" type="primary" @click="handleSave"> - <Icon class="mr-5px" icon="ep:plus" /> - 淇濆瓨 - </el-button> - </template> - </FcDesigner> - </ContentWrap> - - <!-- 琛ㄥ崟淇濆瓨鐨勫脊绐� --> - <Dialog v-model="dialogVisible" title="淇濆瓨琛ㄥ崟" width="600"> - <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> - <el-form-item label="琛ㄥ崟鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ヨ〃鍗曞悕" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import * as FormApi from '@/api/bpm/form' -import FcDesigner from '@form-create/designer' -import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate' -import { useTagsViewStore } from '@/store/modules/tagsView' -import { useFormCreateDesigner } from '@/components/FormCreate' - -defineOptions({ name: 'BpmFormEditor' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅 -const { push, currentRoute } = useRouter() // 璺敱 -const { query } = useRoute() // 璺敱淇℃伅 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 - -const designer = ref() // 琛ㄥ崟璁捐鍣� -useFormCreateDesigner(designer) // 琛ㄥ崟璁捐鍣ㄥ寮� -const dialogVisible = ref(false) // 寮圭獥鏄惁灞曠ず -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛氭彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - name: '', - status: CommonStatusEnum.ENABLE, - remark: '' -}) -const formRules = reactive({ - name: [{ required: true, message: '琛ㄥ崟鍚嶄笉鑳戒负绌�', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 澶勭悊淇濆瓨鎸夐挳 */ -const handleSave = () => { - dialogVisible.value = true -} - -/** 鎻愪氦琛ㄥ崟 */ -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as FormApi.FormVO - data.conf = encodeConf(designer) // 琛ㄥ崟閰嶇疆 - data.fields = encodeFields(designer) // 琛ㄥ崟瀛楁 - if (!data.id) { - await FormApi.createForm(data) - message.success(t('common.createSuccess')) - } else { - await FormApi.updateForm(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - close() - } finally { - formLoading.value = false - } -} -/** 鍏抽棴鎸夐挳 */ -const close = () => { - delView(unref(currentRoute)) - push('/bpm/manager/form') -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - // 鍦烘櫙涓�锛氭柊澧炶〃鍗� - const id = query.id as unknown as number - if (!id) { - return - } - // 鍦烘櫙浜岋細淇敼琛ㄥ崟 - const data = await FormApi.getForm(id) - formData.value = data - setConfAndFields(designer, data.conf, data.fields) -}) -</script> diff --git a/src/views/bpm/form/index.vue b/src/views/bpm/form/index.vue deleted file mode 100644 index 3d542c8..0000000 --- a/src/views/bpm/form/index.vue +++ /dev/null @@ -1,195 +0,0 @@ -<template> - <doc-alert title="瀹℃壒鎺ュ叆锛堟祦绋嬭〃鍗曪級" url="https://doc.iocoder.cn/bpm/use-bpm-form/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="琛ㄥ崟鍚�" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヨ〃鍗曞悕" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['bpm:form:create']" plain type="primary" @click="openForm"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="缂栧彿" prop="id" /> - <el-table-column align="center" label="琛ㄥ崟鍚�" prop="name" /> - <el-table-column align="center" label="鐘舵��" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - /> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['bpm:form:update']" - link - type="primary" - @click="openForm(scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button v-hasPermi="['bpm:form:query']" link @click="openDetail(scope.row.id)"> - 璇︽儏 - </el-button> - <el-button - v-hasPermi="['bpm:form:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟璇︽儏鐨勫脊绐� --> - <Dialog v-model="detailVisible" title="琛ㄥ崟璇︽儏" width="800"> - <form-create :option="detailData.option" :rule="detailData.rule" /> - </Dialog> -</template> - -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as FormApi from '@/api/bpm/form' -import { setConfAndFields2 } from '@/utils/formCreate' - -defineOptions({ name: 'BpmForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const { currentRoute, push } = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await FormApi.getFormPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const openForm = (id?: number) => { - const toRouter: { name: string; query?: { id: number } } = { - name: 'BpmFormEditor' - } - // 琛ㄥ崟鏂板缓鐨勬椂鍊檌d浼犵殑鏄痚vent闇�瑕佹帓闄� - if (typeof id === 'number') { - toRouter.query = { - id - } - } - push(toRouter) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await FormApi.deleteForm(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 璇︽儏鎿嶄綔 */ -const detailVisible = ref(false) -const detailData = ref({ - rule: [], - option: {} -}) -const openDetail = async (rowId: number) => { - // 璁剧疆琛ㄥ崟 - const data = await FormApi.getForm(rowId) - setConfAndFields2(detailData, data.conf, data.fields) - // 寮圭獥鎵撳紑 - detailVisible.value = true -} -/**琛ㄥ崟淇濆瓨杩斿洖鍚庨噸鏂板姞杞藉垪琛� */ -watch( - () => currentRoute.value, - () => { - getList() - }, - { - immediate: true - } -) -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/group/UserGroupForm.vue b/src/views/bpm/group/UserGroupForm.vue deleted file mode 100644 index ac0cfcb..0000000 --- a/src/views/bpm/group/UserGroupForm.vue +++ /dev/null @@ -1,132 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="缁勫悕" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ粍鍚�" /> - </el-form-item> - <el-form-item label="鎻忚堪"> - <el-input v-model="formData.description" placeholder="璇疯緭鍏ユ弿杩�" type="textarea" /> - </el-form-item> - <el-form-item label="鎴愬憳" prop="userIds"> - <el-select v-model="formData.userIds" multiple placeholder="璇烽�夋嫨鎴愬憳"> - <el-option - v-for="user in userList" - :key="user.id" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import * as UserGroupApi from '@/api/bpm/userGroup' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'UserGroupForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - description: undefined, - userIds: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '缁勫悕涓嶈兘涓虹┖', trigger: 'blur' }], - description: [{ required: true, message: '鎻忚堪涓嶈兘涓虹┖', trigger: 'blur' }], - userIds: [{ required: true, message: '鎴愬憳涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await UserGroupApi.getUserGroup(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as UserGroupApi.UserGroupVO - if (formType.value === 'create') { - await UserGroupApi.createUserGroup(data) - message.success(t('common.createSuccess')) - } else { - await UserGroupApi.updateUserGroup(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - description: undefined, - userIds: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/group/index.vue b/src/views/bpm/group/index.vue deleted file mode 100644 index 62785a9..0000000 --- a/src/views/bpm/group/index.vue +++ /dev/null @@ -1,191 +0,0 @@ -<template> - <doc-alert title="宸ヤ綔娴佹墜鍐�" url="https://doc.iocoder.cn/bpm/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="缁勫悕" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ョ粍鍚�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['bpm:user-group:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="缁勫悕" align="center" prop="name" /> - <el-table-column label="鎻忚堪" align="center" prop="description" /> - <el-table-column label="鎴愬憳" align="center"> - <template #default="scope"> - <span v-for="userId in scope.row.userIds" :key="userId" class="pr-5px"> - {{ userList.find((user) => user.id === userId)?.nickname }} - </span> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['bpm:user-group:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['bpm:user-group:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <UserGroupForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as UserGroupApi from '@/api/bpm/userGroup' -import * as UserApi from '@/api/system/user' -import UserGroupForm from './UserGroupForm.vue' -import { UserVO } from '@/api/system/user' - -defineOptions({ name: 'BpmUserGroup' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await UserGroupApi.getUserGroupPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await UserGroupApi.deleteUserGroup(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/bpm/model/ModelForm.vue b/src/views/bpm/model/ModelForm.vue deleted file mode 100644 index ce60edc..0000000 --- a/src/views/bpm/model/ModelForm.vue +++ /dev/null @@ -1,239 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="600"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="娴佺▼鏍囪瘑" prop="key"> - <el-input - v-model="formData.key" - :disabled="!!formData.id" - placeholder="璇疯緭鍏ユ祦鏍囨爣璇�" - style="width: 330px" - /> - <el-tooltip - v-if="!formData.id" - class="item" - content="鏂板缓鍚庯紝娴佺▼鏍囪瘑涓嶅彲淇敼锛�" - effect="light" - placement="top" - > - <i class="el-icon-question" style="padding-left: 5px"></i> - </el-tooltip> - <el-tooltip v-else class="item" content="娴佺▼鏍囪瘑涓嶅彲淇敼锛�" effect="light" placement="top"> - <i class="el-icon-question" style="padding-left: 5px"></i> - </el-tooltip> - </el-form-item> - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input - v-model="formData.name" - :disabled="!!formData.id" - clearable - placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" - /> - </el-form-item> - <el-form-item v-if="formData.id" label="娴佺▼鍒嗙被" prop="category"> - <el-select - v-model="formData.category" - clearable - placeholder="璇烽�夋嫨娴佺▼鍒嗙被" - style="width: 100%" - > - <el-option - v-for="category in categoryList" - :key="category.code" - :label="category.name" - :value="category.code" - /> - </el-select> - </el-form-item> - <el-form-item v-if="formData.id" label="娴佺▼鍥炬爣" prop="icon"> - <UploadImg v-model="formData.icon" :limit="1" height="128px" width="128px" /> - </el-form-item> - <el-form-item label="娴佺▼鎻忚堪" prop="description"> - <el-input v-model="formData.description" clearable type="textarea" /> - </el-form-item> - <div v-if="formData.id"> - <el-form-item label="琛ㄥ崟绫诲瀷" prop="formType"> - <el-radio-group v-model="formData.formType"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_MODEL_FORM_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item v-if="formData.formType === 10" label="娴佺▼琛ㄥ崟" prop="formId"> - <el-select v-model="formData.formId" clearable style="width: 100%"> - <el-option - v-for="form in formList" - :key="form.id" - :label="form.name" - :value="form.id" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="formData.formType === 20" - label="琛ㄥ崟鎻愪氦璺敱" - prop="formCustomCreatePath" - > - <el-input - v-model="formData.formCustomCreatePath" - placeholder="璇疯緭鍏ヨ〃鍗曟彁浜よ矾鐢�" - style="width: 330px" - /> - <el-tooltip - class="item" - content="鑷畾涔夎〃鍗曠殑鎻愪氦璺緞锛屼娇鐢� Vue 鐨勮矾鐢卞湴鍧�锛屼緥濡傝锛歜pm/oa/leave/create" - effect="light" - placement="top" - > - <i class="el-icon-question" style="padding-left: 5px"></i> - </el-tooltip> - </el-form-item> - <el-form-item - v-if="formData.formType === 20" - label="琛ㄥ崟鏌ョ湅鍦板潃" - prop="formCustomViewPath" - > - <el-input - v-model="formData.formCustomViewPath" - placeholder="璇疯緭鍏ヨ〃鍗曟煡鐪嬬殑缁勪欢鍦板潃" - style="width: 330px" - /> - <el-tooltip - class="item" - content="鑷畾涔夎〃鍗曠殑鏌ョ湅缁勪欢鍦板潃锛屼娇鐢� Vue 鐨勭粍浠跺湴鍧�锛屼緥濡傝锛歜pm/oa/leave/detail" - effect="light" - placement="top" - > - <i class="el-icon-question" style="padding-left: 5px"></i> - </el-tooltip> - </el-form-item> - </div> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { ElMessageBox } from 'element-plus' -import * as ModelApi from '@/api/bpm/model' -import * as FormApi from '@/api/bpm/form' -import { CategoryApi } from '@/api/bpm/category' - -defineOptions({ name: 'ModelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - formType: 10, - name: '', - category: undefined, - icon: undefined, - description: '', - formId: '', - formCustomCreatePath: '', - formCustomViewPath: '' -}) -const formRules = reactive({ - name: [{ required: true, message: '鍙傛暟鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - key: [{ required: true, message: '鍙傛暟閿悕涓嶈兘涓虹┖', trigger: 'blur' }], - category: [{ required: true, message: '鍙傛暟鍒嗙被涓嶈兘涓虹┖', trigger: 'blur' }], - icon: [{ required: true, message: '鍙傛暟鍥炬爣涓嶈兘涓虹┖', trigger: 'blur' }], - value: [{ required: true, message: '鍙傛暟閿�间笉鑳戒负绌�', trigger: 'blur' }], - visible: [{ required: true, message: '鏄惁鍙涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const formList = ref([]) // 娴佺▼琛ㄥ崟鐨勪笅鎷夋鐨勬暟鎹� -const categoryList = ref([]) // 娴佺▼鍒嗙被鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ModelApi.getModel(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱娴佺▼琛ㄥ崟鐨勪笅鎷夋鐨勬暟鎹� - formList.value = await FormApi.getFormSimpleList() - // 鏌ヨ娴佺▼鍒嗙被鍒楄〃 - categoryList.value = await CategoryApi.getCategorySimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ModelApi.ModelVO - if (formType.value === 'create') { - await ModelApi.createModel(data) - // 鎻愮ず锛屽紩瀵肩敤鎴峰仛鍚庣画鐨勬搷浣� - await ElMessageBox.alert( - '<strong>鏂板缓妯″瀷鎴愬姛锛�</strong>鍚庣画闇�瑕佹墽琛屽涓� 3 涓楠わ細' + - '<div>1. 鐐瑰嚮銆愪慨鏀规祦绋嬨�戞寜閽紝閰嶇疆娴佺▼鐨勫垎绫汇�佽〃鍗曚俊鎭�</div>' + - '<div>2. 鐐瑰嚮銆愯璁℃祦绋嬨�戞寜閽紝缁樺埗娴佺▼鍥�</div>' + - '<div>3. 鐐瑰嚮銆愬彂甯冩祦绋嬨�戞寜閽紝瀹屾垚娴佺▼鐨勬渶缁堝彂甯�</div>' + - '鍙﹀锛屾瘡娆℃祦绋嬩慨鏀瑰悗锛岄兘闇�瑕佺偣鍑汇�愬彂甯冩祦绋嬨�戞寜閽紝鎵嶈兘姝e紡鐢熸晥锛侊紒锛�', - '閲嶈鎻愮ず', - { - dangerouslyUseHTMLString: true, - type: 'success' - } - ) - } else { - await ModelApi.updateModel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - formType: 10, - name: '', - category: undefined, - icon: '', - description: '', - formId: '', - formCustomCreatePath: '', - formCustomViewPath: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/model/ModelImportForm.vue b/src/views/bpm/model/ModelImportForm.vue deleted file mode 100644 index 9a91e1d..0000000 --- a/src/views/bpm/model/ModelImportForm.vue +++ /dev/null @@ -1,141 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="瀵煎叆娴佺▼" width="400"> - <div> - <el-upload - ref="uploadRef" - v-model:file-list="fileList" - :action="importUrl" - :auto-upload="false" - :data="formData" - :disabled="formLoading" - :headers="uploadHeaders" - :limit="1" - :on-error="submitFormError" - :on-exceed="handleExceed" - :on-success="submitFormSuccess" - accept=".bpmn, .xml" - drag - name="bpmnFile" - > - <Icon class="el-icon--upload" icon="ep:upload-filled" /> - <div class="el-upload__text"> 灏嗘枃浠舵嫋鍒版澶勶紝鎴� <em>鐐瑰嚮涓婁紶</em></div> - <template #tip> - <div class="el-upload__tip" style="color: red"> - 鎻愮ず锛氫粎鍏佽瀵煎叆鈥渂pm鈥濇垨鈥渪ml鈥濇牸寮忔枃浠讹紒 - </div> - <div> - <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px"> - <el-form-item label="娴佺▼鏍囪瘑" prop="key"> - <el-input - v-model="formData.key" - placeholder="璇疯緭鍏ユ祦鏍囨爣璇�" - style="width: 250px" - /> - </el-form-item> - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input v-model="formData.name" clearable placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" /> - </el-form-item> - <el-form-item label="娴佺▼鎻忚堪" prop="description"> - <el-input v-model="formData.description" clearable type="textarea" /> - </el-form-item> - </el-form> - </div> - </template> - </el-upload> - </div> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { getAccessToken, getTenantId } from '@/utils/auth' - -defineOptions({ name: 'ModelImportForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - key: '', - name: '', - description: '' -}) -const formRules = reactive({ - key: [{ required: true, message: '娴佺▼鏍囪瘑涓嶈兘涓虹┖', trigger: 'blur' }], - name: [{ required: true, message: '娴佺▼鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const uploadRef = ref() // 涓婁紶 Ref -const importUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/bpm/model/import' -const uploadHeaders = ref() // 涓婁紶 Header 澶� -const fileList = ref([]) // 鏂囦欢鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - resetForm() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - if (fileList.value.length == 0) { - message.error('璇蜂笂浼犳枃浠�') - return - } - // 鎻愪氦璇锋眰 - uploadHeaders.value = { - Authorization: 'Bearer ' + getAccessToken(), - 'tenant-id': getTenantId() - } - formLoading.value = true - uploadRef.value!.submit() -} - -/** 鏂囦欢涓婁紶鎴愬姛 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitFormSuccess = async (response: any) => { - if (response.code !== 0) { - message.error(response.msg) - formLoading.value = false - return - } - // 鎻愮ず鎴愬姛 - message.success('瀵煎叆娴佺▼鎴愬姛锛佽鐐瑰嚮銆愯璁℃祦绋嬨�戞寜閽紝杩涜缂栬緫淇濆瓨鍚庯紝鎵嶅彲浠ヨ繘琛屻�愬彂甯冩祦绋嬨��') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') -} - -/** 涓婁紶閿欒鎻愮ず */ -const submitFormError = (): void => { - message.error('瀵煎叆娴佺▼澶辫触锛岃鎮ㄩ噸鏂颁笂浼狅紒') - formLoading.value = false -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - // 閲嶇疆涓婁紶鐘舵�佸拰鏂囦欢 - formLoading.value = false - uploadRef.value?.clearFiles() - // 閲嶇疆琛ㄥ崟 - formData.value = { - key: '', - name: '', - description: '' - } - formRef.value?.resetFields() -} - -/** 鏂囦欢鏁拌秴鍑烘彁绀� */ -const handleExceed = (): void => { - message.error('鏈�澶氬彧鑳戒笂浼犱竴涓枃浠讹紒') -} -</script> diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue deleted file mode 100644 index 29bca71..0000000 --- a/src/views/bpm/model/editor/index.vue +++ /dev/null @@ -1,115 +0,0 @@ -<template> - <ContentWrap> - <!-- 娴佺▼璁捐鍣紝璐熻矗缁樺埗娴佺▼绛� --> - <MyProcessDesigner - key="designer" - v-if="xmlString !== undefined" - v-model="xmlString" - :value="xmlString" - v-bind="controlForm" - keyboard - ref="processDesigner" - @init-finished="initModeler" - :additionalModel="controlForm.additionalModel" - @save="save" - /> - <!-- 娴佺▼灞炴�у櫒锛岃礋璐g紪杈戞瘡涓祦绋嬭妭鐐圭殑灞炴�� --> - <MyProcessPenal - key="penal" - :bpmnModeler="modeler as any" - :prefix="controlForm.prefix" - class="process-panel" - :model="model" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { MyProcessDesigner, MyProcessPenal } from '@/components/bpmnProcessDesigner/package' -// 鑷畾涔夊厓绱犻�変腑鏃剁殑寮瑰嚭鑿滃崟锛堜慨鏀� 榛樿浠诲姟 涓� 鐢ㄦ埛浠诲姟锛� -import CustomContentPadProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/content-pad' -// 鑷畾涔夊乏渚ц彍鍗曪紙淇敼 榛樿浠诲姟 涓� 鐢ㄦ埛浠诲姟锛� -import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette' -import * as ModelApi from '@/api/bpm/model' - -defineOptions({ name: 'BpmModelEditor' }) - -const router = useRouter() // 璺敱 -const { query } = useRoute() // 璺敱鐨勬煡璇� -const message = useMessage() // 鍥介檯鍖� - -const xmlString = ref(undefined) // BPMN XML -const modeler = ref(null) // BPMN Modeler -const controlForm = ref({ - simulation: true, - labelEditing: false, - labelVisible: false, - prefix: 'flowable', - headerButtonSize: 'mini', - additionalModel: [CustomContentPadProvider, CustomPaletteProvider] -}) -const model = ref<ModelApi.ModelVO>() // 娴佺▼妯″瀷鐨勪俊鎭� - -/** 鍒濆鍖� modeler */ -const initModeler = (item) => { - setTimeout(() => { - modeler.value = item - }, 10) -} - -/** 娣诲姞/淇敼妯″瀷 */ -const save = async (bpmnXml) => { - const data = { - ...model.value, - bpmnXml: bpmnXml // bpmnXml 鍙槸鍒濆鍖栨祦绋嬪浘锛屽悗缁慨鏀规棤娉曢�氳繃瀹冭幏寰� - } as unknown as ModelApi.ModelVO - // 鎻愪氦 - if (data.id) { - await ModelApi.updateModel(data) - message.success('淇敼鎴愬姛') - } else { - await ModelApi.createModel(data) - message.success('鏂板鎴愬姛') - } - // 璺宠浆鍥炲幓 - close() -} - -/** 鍏抽棴鎸夐挳 */ -const close = () => { - router.push({ path: '/bpm/manager/model' }) -} - -/** 鍒濆鍖� */ -onMounted(async () => { - const modelId = query.modelId as unknown as number - if (!modelId) { - message.error('缂哄皯妯″瀷 modelId 缂栧彿') - return - } - // 鏌ヨ妯″瀷 - const data = await ModelApi.getModel(modelId) - if (!data.bpmnXml) { - // 棣栨鍒涘缓鐨� Model 妯″瀷锛屽畠鏄病鏈� bpmnXml锛屾鏃堕渶瑕佺粰瀹冧竴涓粯璁ょ殑 - data.bpmnXml = ` <?xml version="1.0" encoding="UTF-8"?> -<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.activiti.org/processdef"> - <process id="${data.key}" name="${data.name}" isExecutable="true" /> - <bpmndi:BPMNDiagram id="BPMNDiagram"> - <bpmndi:BPMNPlane id="${data.key}_di" bpmnElement="${data.key}" /> - </bpmndi:BPMNDiagram> -</definitions>` - } - model.value = { - ...data, - bpmnXml: undefined // 娓呯┖ bpmnXml 灞炴�� - } - xmlString.value = data.bpmnXml -}) -</script> -<style lang="scss"> -.process-panel__container { - position: absolute; - top: 90px; - right: 60px; -} -</style> diff --git a/src/views/bpm/model/index.vue b/src/views/bpm/model/index.vue deleted file mode 100644 index e4ba6d4..0000000 --- a/src/views/bpm/model/index.vue +++ /dev/null @@ -1,415 +0,0 @@ -<template> - <doc-alert title="娴佺▼璁捐鍣紙BPMN锛�" url="https://doc.iocoder.cn/bpm/model-designer-dingding/" /> - <doc-alert - title="娴佺▼璁捐鍣紙閽夐拤銆侀涔︼級" - url="https://doc.iocoder.cn/bpm/model-designer-bpmn/" - /> - <doc-alert title="閫夋嫨瀹℃壒浜恒�佸彂璧蜂汉鑷��" url="https://doc.iocoder.cn/bpm/assignee/" /> - <doc-alert title="浼氱銆佹垨绛俱�佷緷娆″鎵�" url="https://doc.iocoder.cn/bpm/multi-instance/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娴佺▼鏍囪瘑" prop="key"> - <el-input - v-model="queryParams.key" - placeholder="璇疯緭鍏ユ祦绋嬫爣璇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娴佺▼鍒嗙被" prop="category"> - <el-select - v-model="queryParams.category" - placeholder="璇烽�夋嫨娴佺▼鍒嗙被" - clearable - class="!w-240px" - > - <el-option - v-for="category in categoryList" - :key="category.code" - :label="category.name" - :value="category.code" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['bpm:model:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板缓娴佺▼ - </el-button> - <el-button type="success" plain @click="openImportForm" v-hasPermi="['bpm:model:import']"> - <Icon icon="ep:upload" class="mr-5px" /> 瀵煎叆娴佺▼ - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="娴佺▼鏍囪瘑" align="center" prop="key" width="200" /> - <el-table-column label="娴佺▼鍚嶇О" align="center" prop="name" width="200"> - <template #default="scope"> - <el-button type="primary" link @click="handleBpmnDetail(scope.row)"> - <span>{{ scope.row.name }}</span> - </el-button> - </template> - </el-table-column> - <el-table-column label="娴佺▼鍥炬爣" align="center" prop="icon" width="100"> - <template #default="scope"> - <el-image :src="scope.row.icon" class="w-32px h-32px" /> - </template> - </el-table-column> - <el-table-column label="娴佺▼鍒嗙被" align="center" prop="categoryName" width="100" /> - <el-table-column label="琛ㄥ崟淇℃伅" align="center" prop="formType" width="200"> - <template #default="scope"> - <el-button - v-if="scope.row.formType === 10" - type="primary" - link - @click="handleFormDetail(scope.row)" - > - <span>{{ scope.row.formName }}</span> - </el-button> - <el-button - v-else-if="scope.row.formType === 20" - type="primary" - link - @click="handleFormDetail(scope.row)" - > - <span>{{ scope.row.formCustomCreatePath }}</span> - </el-button> - <label v-else>鏆傛棤琛ㄥ崟</label> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏈�鏂伴儴缃茬殑娴佺▼瀹氫箟" align="center"> - <el-table-column - label="娴佺▼鐗堟湰" - align="center" - prop="processDefinition.version" - width="100" - > - <template #default="scope"> - <el-tag v-if="scope.row.processDefinition"> - v{{ scope.row.processDefinition.version }} - </el-tag> - <el-tag v-else type="warning">鏈儴缃�</el-tag> - </template> - </el-table-column> - <el-table-column - label="婵�娲荤姸鎬�" - align="center" - prop="processDefinition.version" - width="85" - > - <template #default="scope"> - <el-switch - v-if="scope.row.processDefinition" - v-model="scope.row.processDefinition.suspensionState" - :active-value="1" - :inactive-value="2" - @change="handleChangeState(scope.row)" - /> - </template> - </el-table-column> - <el-table-column label="閮ㄧ讲鏃堕棿" align="center" prop="deploymentTime" width="180"> - <template #default="scope"> - <span v-if="scope.row.processDefinition"> - {{ formatDate(scope.row.processDefinition.deploymentTime) }} - </span> - </template> - </el-table-column> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" width="240" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['bpm:model:update']" - > - 淇敼娴佺▼ - </el-button> - <el-button - link - type="primary" - @click="handleDesign(scope.row)" - v-hasPermi="['bpm:model:update']" - > - 璁捐娴佺▼ - </el-button> - <el-button - link - type="primary" - @click="handleSimpleDesign(scope.row.id)" - v-hasPermi="['bpm:model:update']" - > - 浠块拤閽夎璁℃祦绋� - </el-button> - <el-button - link - type="primary" - @click="handleDeploy(scope.row)" - v-hasPermi="['bpm:model:deploy']" - > - 鍙戝竷娴佺▼ - </el-button> - <el-button - link - type="primary" - v-hasPermi="['bpm:process-definition:query']" - @click="handleDefinitionList(scope.row)" - > - 娴佺▼瀹氫箟 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['bpm:model:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼娴佺▼ --> - <ModelForm ref="formRef" @success="getList" /> - - <!-- 琛ㄥ崟寮圭獥锛氬鍏ユ祦绋� --> - <ModelImportForm ref="importFormRef" @success="getList" /> - - <!-- 寮圭獥锛氳〃鍗曡鎯� --> - <Dialog title="琛ㄥ崟璇︽儏" v-model="formDetailVisible" width="800"> - <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" /> - </Dialog> - - <!-- 寮圭獥锛氭祦绋嬫ā鍨嬪浘鐨勯瑙� --> - <Dialog title="娴佺▼鍥�" v-model="bpmnDetailVisible" width="800"> - <MyProcessViewer - key="designer" - v-model="bpmnXML" - :value="bpmnXML as any" - v-bind="bpmnControlForm" - :prefix="bpmnControlForm.prefix" - /> - </Dialog> -</template> - -<script lang="ts" setup> -import { dateFormatter, formatDate } from '@/utils/formatTime' -import { MyProcessViewer } from '@/components/bpmnProcessDesigner/package' -import * as ModelApi from '@/api/bpm/model' -import * as FormApi from '@/api/bpm/form' -import ModelForm from './ModelForm.vue' -import ModelImportForm from '@/views/bpm/model/ModelImportForm.vue' -import { setConfAndFields2 } from '@/utils/formCreate' -import { CategoryApi } from '@/api/bpm/category' - -defineOptions({ name: 'BpmModel' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const { push } = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - key: undefined, - name: undefined, - category: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const categoryList = ref([]) // 娴佺▼鍒嗙被鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ModelApi.getModelPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const importFormRef = ref() -const openImportForm = () => { - importFormRef.value.open() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ModelApi.deleteModel(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鏇存柊鐘舵�佹搷浣� */ -const handleChangeState = async (row) => { - const state = row.processDefinition.suspensionState - try { - // 淇敼鐘舵�佺殑浜屾纭 - const id = row.id - const statusState = state === 1 ? '婵�娲�' : '鎸傝捣' - const content = '鏄惁纭' + statusState + '娴佺▼鍚嶅瓧涓�"' + row.name + '"鐨勬暟鎹」?' - await message.confirm(content) - // 鍙戣捣淇敼鐘舵�� - await ModelApi.updateModelState(id, state) - // 鍒锋柊鍒楄〃 - await getList() - } catch { - // 鍙栨秷鍚庯紝杩涜鎭㈠鎸夐挳 - row.processDefinition.suspensionState = state === 1 ? 2 : 1 - } -} - -/** 璁捐娴佺▼ */ -const handleDesign = (row) => { - push({ - name: 'BpmModelEditor', - query: { - modelId: row.id - } - }) -} - -const handleSimpleDesign = (row) => { - push({ - name: 'SimpleWorkflowDesignEditor', - query: { - modelId: row.id - } - }) -} - -/** 鍙戝竷娴佺▼ */ -const handleDeploy = async (row) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.confirm('鏄惁閮ㄧ讲璇ユ祦绋嬶紒锛�') - // 鍙戣捣閮ㄧ讲 - await ModelApi.deployModel(row.id) - message.success(t('閮ㄧ讲鎴愬姛')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 璺宠浆鍒版寚瀹氭祦绋嬪畾涔夊垪琛� */ -const handleDefinitionList = (row) => { - push({ - name: 'BpmProcessDefinition', - query: { - key: row.key - } - }) -} - -/** 娴佺▼琛ㄥ崟鐨勮鎯呮寜閽搷浣� */ -const formDetailVisible = ref(false) -const formDetailPreview = ref({ - rule: [], - option: {} -}) -const handleFormDetail = async (row) => { - if (row.formType == 10) { - // 璁剧疆琛ㄥ崟 - const data = await FormApi.getForm(row.formId) - setConfAndFields2(formDetailPreview, data.conf, data.fields) - // 寮圭獥鎵撳紑 - formDetailVisible.value = true - } else { - await push({ - path: row.formCustomCreatePath - }) - } -} - -/** 娴佺▼鍥剧殑璇︽儏鎸夐挳鎿嶄綔 */ -const bpmnDetailVisible = ref(false) -const bpmnXML = ref(null) -const bpmnControlForm = ref({ - prefix: 'flowable' -}) -const handleBpmnDetail = async (row) => { - const data = await ModelApi.getModel(row.id) - bpmnXML.value = data.bpmnXml || '' - bpmnDetailVisible.value = true -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鏌ヨ娴佺▼鍒嗙被鍒楄〃 - categoryList.value = await CategoryApi.getCategorySimpleList() -}) -</script> diff --git a/src/views/bpm/oa/leave/create.vue b/src/views/bpm/oa/leave/create.vue deleted file mode 100644 index 28a15af..0000000 --- a/src/views/bpm/oa/leave/create.vue +++ /dev/null @@ -1,164 +0,0 @@ -<template> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - > - <el-form-item label="璇峰亣绫诲瀷" prop="type"> - <el-select v-model="formData.type" clearable placeholder="璇烽�夋嫨璇峰亣绫诲瀷"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="寮�濮嬫椂闂�" prop="startTime"> - <el-date-picker - v-model="formData.startTime" - clearable - placeholder="璇烽�夋嫨寮�濮嬫椂闂�" - type="datetime" - value-format="x" - /> - </el-form-item> - <el-form-item label="缁撴潫鏃堕棿" prop="endTime"> - <el-date-picker - v-model="formData.endTime" - clearable - placeholder="璇烽�夋嫨缁撴潫鏃堕棿" - type="datetime" - value-format="x" - /> - </el-form-item> - <el-form-item label="鍘熷洜" prop="reason"> - <el-input v-model="formData.reason" placeholder="璇疯緭璇峰亣鍘熷洜" type="textarea" /> - </el-form-item> - <el-col v-if="startUserSelectTasks.length > 0"> - <el-card class="mb-10px"> - <template #header>鎸囧畾瀹℃壒浜�</template> - <el-form - :model="startUserSelectAssignees" - :rules="startUserSelectAssigneesFormRules" - ref="startUserSelectAssigneesFormRef" - > - <el-form-item - v-for="userTask in startUserSelectTasks" - :key="userTask.id" - :label="`浠诲姟銆�${userTask.name}銆慲" - :prop="userTask.id" - > - <el-select - v-model="startUserSelectAssignees[userTask.id]" - multiple - placeholder="璇烽�夋嫨瀹℃壒浜�" - > - <el-option - v-for="user in userList" - :key="user.id" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - </el-form> - </el-card> - </el-col> - <el-form-item> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - </el-form-item> - </el-form> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as LeaveApi from '@/api/bpm/leave' -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as DefinitionApi from '@/api/bpm/definition' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'BpmOALeaveCreate' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { push, currentRoute } = useRouter() // 璺敱 - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - type: undefined, - reason: undefined, - startTime: undefined, - endTime: undefined -}) -const formRules = reactive({ - type: [{ required: true, message: '璇峰亣绫诲瀷涓嶈兘涓虹┖', trigger: 'blur' }], - reason: [{ required: true, message: '璇峰亣鍘熷洜涓嶈兘涓虹┖', trigger: 'change' }], - startTime: [{ required: true, message: '璇峰亣寮�濮嬫椂闂翠笉鑳戒负绌�', trigger: 'change' }], - endTime: [{ required: true, message: '璇峰亣缁撴潫鏃堕棿涓嶈兘涓虹┖', trigger: 'change' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -// 鎸囧畾瀹℃壒浜� -const processDefineKey = 'oa_leave' // 娴佺▼瀹氫箟 Key -const startUserSelectTasks = ref([]) // 鍙戣捣浜洪渶瑕侀�夋嫨瀹℃壒浜虹殑鐢ㄦ埛浠诲姟鍒楄〃 -const startUserSelectAssignees = ref({}) // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑鏁版嵁 -const startUserSelectAssigneesFormRef = ref() // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑琛ㄥ崟 Ref -const startUserSelectAssigneesFormRules = ref({}) // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑琛ㄥ崟 Rules -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎻愪氦琛ㄥ崟 */ -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鏍¢獙鎸囧畾瀹℃壒浜� - if (startUserSelectTasks.value?.length > 0) { - await startUserSelectAssigneesFormRef.value.validate() - } - - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } as unknown as LeaveApi.LeaveVO - // 璁剧疆鎸囧畾瀹℃壒浜� - if (startUserSelectTasks.value?.length > 0) { - data.startUserSelectAssignees = startUserSelectAssignees.value - } - await LeaveApi.createLeave(data) - message.success('鍙戣捣鎴愬姛') - // 鍏抽棴褰撳墠 Tab - delView(unref(currentRoute)) - await push({ name: 'BpmOALeave' }) - } finally { - formLoading.value = false - } -} - -/** 鍒濆鍖� */ -onMounted(async () => { - const processDefinitionDetail = await DefinitionApi.getProcessDefinition( - undefined, - processDefineKey - ) - if (!processDefinitionDetail) { - message.error('OA 璇峰亣鐨勬祦绋嬫ā鍨嬫湭閰嶇疆锛岃妫�鏌ワ紒') - return - } - startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks - // 璁剧疆鎸囧畾瀹℃壒浜� - if (startUserSelectTasks.value?.length > 0) { - // 璁剧疆鏍¢獙瑙勫垯 - for (const userTask of startUserSelectTasks.value) { - startUserSelectAssignees.value[userTask.id] = [] - startUserSelectAssigneesFormRules.value[userTask.id] = [ - { required: true, message: '璇烽�夋嫨瀹℃壒浜�', trigger: 'blur' } - ] - } - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - } -}) -</script> diff --git a/src/views/bpm/oa/leave/detail.vue b/src/views/bpm/oa/leave/detail.vue deleted file mode 100644 index 87036d8..0000000 --- a/src/views/bpm/oa/leave/detail.vue +++ /dev/null @@ -1,51 +0,0 @@ -<template> - <ContentWrap> - <el-descriptions :column="1" border> - <el-descriptions-item label="璇峰亣绫诲瀷"> - <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="detailData.type" /> - </el-descriptions-item> - <el-descriptions-item label="寮�濮嬫椂闂�"> - {{ formatDate(detailData.startTime, 'YYYY-MM-DD') }} - </el-descriptions-item> - <el-descriptions-item label="缁撴潫鏃堕棿"> - {{ formatDate(detailData.endTime, 'YYYY-MM-DD') }} - </el-descriptions-item> - <el-descriptions-item label="鍘熷洜"> - {{ detailData.reason }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import { propTypes } from '@/utils/propTypes' -import * as LeaveApi from '@/api/bpm/leave' - -defineOptions({ name: 'BpmOALeaveDetail' }) - -const { query } = useRoute() // 鏌ヨ鍙傛暟 - -const props = defineProps({ - id: propTypes.number.def(undefined) -}) -const detailLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const detailData = ref<any>({}) // 璇︽儏鏁版嵁 -const queryId = query.id as unknown as number // 浠� URL 浼犻�掕繃鏉ョ殑 id 缂栧彿 - -/** 鑾峰緱鏁版嵁 */ -const getInfo = async () => { - detailLoading.value = true - try { - detailData.value = await LeaveApi.getLeave(props.id || queryId) - } finally { - detailLoading.value = false - } -} -defineExpose({ open: getInfo }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鍒濆鍖� **/ -onMounted(() => { - getInfo() -}) -</script> diff --git a/src/views/bpm/oa/leave/index.vue b/src/views/bpm/oa/leave/index.vue deleted file mode 100644 index 27dbc19..0000000 --- a/src/views/bpm/oa/leave/index.vue +++ /dev/null @@ -1,257 +0,0 @@ -<template> - <doc-alert title="瀹℃壒鎺ュ叆锛堜笟鍔¤〃鍗曪級" url="https://doc.iocoder.cn/bpm/use-business-form/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="璇峰亣绫诲瀷" prop="type"> - <el-select - v-model="queryParams.type" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨璇峰亣绫诲瀷" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐢宠鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="瀹℃壒缁撴灉" prop="status"> - <el-select - v-model="queryParams.status" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨瀹℃壒缁撴灉" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍘熷洜" prop="reason"> - <el-input - v-model="queryParams.reason" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ師鍥�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button plain type="primary" @click="handleCreate()"> - <Icon class="mr-5px" icon="ep:plus" /> - 鍙戣捣璇峰亣 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="鐢宠缂栧彿" prop="id" /> - <el-table-column align="center" label="鐘舵��" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="寮�濮嬫椂闂�" - prop="startTime" - width="180" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="缁撴潫鏃堕棿" - prop="endTime" - width="180" - /> - <el-table-column align="center" label="璇峰亣绫诲瀷" prop="type"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column align="center" label="鍘熷洜" prop="reason" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鐢宠鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="鎿嶄綔" width="200"> - <template #default="scope"> - <el-button - v-hasPermi="['bpm:oa-leave:query']" - link - type="primary" - @click="handleDetail(scope.row)" - > - 璇︽儏 - </el-button> - <el-button - v-hasPermi="['bpm:oa-leave:query']" - link - type="primary" - @click="handleProcessDetail(scope.row)" - > - 杩涘害 - </el-button> - <el-button - v-if="scope.row.result === 1" - v-hasPermi="['bpm:oa-leave:create']" - link - type="danger" - @click="cancelLeave(scope.row)" - > - 鍙栨秷 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as LeaveApi from '@/api/bpm/leave' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' - -defineOptions({ name: 'BpmOALeave' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const router = useRouter() // 璺敱 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - type: undefined, - status: undefined, - reason: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await LeaveApi.getLeavePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞鎿嶄綔 */ -const handleCreate = () => { - router.push({ name: 'OALeaveCreate' }) -} - -/** 璇︽儏鎿嶄綔 */ -const handleDetail = (row: LeaveApi.LeaveVO) => { - router.push({ - name: 'OALeaveDetail', - query: { - id: row.id - } - }) -} - -/** 鍙栨秷璇峰亣鎿嶄綔 */ -const cancelLeave = async (row) => { - // 浜屾纭 - const { value } = await ElMessageBox.prompt('璇疯緭鍏ュ彇娑堝師鍥�', '鍙栨秷娴佺▼', { - confirmButtonText: t('common.ok'), - cancelButtonText: t('common.cancel'), - inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 鍒ゆ柇闈炵┖锛屼笖闈炵┖鏍� - inputErrorMessage: '鍙栨秷鍘熷洜涓嶈兘涓虹┖' - }) - // 鍙戣捣鍙栨秷 - await ProcessInstanceApi.cancelProcessInstanceByStartUser(row.id, value) - message.success('鍙栨秷鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() -} - -/** 瀹℃壒杩涘害 */ -const handleProcessDetail = (row) => { - router.push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.processInstanceId - } - }) -} - -// fix: 鍒楄〃涓嶅埛鏂扮殑闂銆� -watch( - () => router.currentRoute.value, - () => { - getList() - } -) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/processExpression/ProcessExpressionForm.vue b/src/views/bpm/processExpression/ProcessExpressionForm.vue deleted file mode 100644 index acf0667..0000000 --- a/src/views/bpm/processExpression/ProcessExpressionForm.vue +++ /dev/null @@ -1,114 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍚嶅瓧" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕瀛�" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="琛ㄨ揪寮�" prop="expression"> - <el-input type="textarea" v-model="formData.expression" placeholder="璇疯緭鍏ヨ〃杈惧紡" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { ProcessExpressionApi, ProcessExpressionVO } from '@/api/bpm/processExpression' -import { CommonStatusEnum } from '@/utils/constants' - -/** BPM 娴佺▼ 琛ㄥ崟 */ -defineOptions({ name: 'ProcessExpressionForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - status: undefined, - expression: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶅瓧涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - expression: [{ required: true, message: '琛ㄨ揪寮忎笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProcessExpressionApi.getProcessExpression(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProcessExpressionVO - if (formType.value === 'create') { - await ProcessExpressionApi.createProcessExpression(data) - message.success(t('common.createSuccess')) - } else { - await ProcessExpressionApi.updateProcessExpression(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - status: CommonStatusEnum.ENABLE, - expression: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processExpression/index.vue b/src/views/bpm/processExpression/index.vue deleted file mode 100644 index ec2de5a..0000000 --- a/src/views/bpm/processExpression/index.vue +++ /dev/null @@ -1,182 +0,0 @@ -<template> - <doc-alert title="娴佺▼琛ㄨ揪寮�" url="https://doc.iocoder.cn/bpm/expression/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶅瓧" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕瀛�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['bpm:process-expression:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="鍚嶅瓧" align="center" prop="name" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="琛ㄨ揪寮�" align="center" prop="expression" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['bpm:process-expression:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['bpm:process-expression:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProcessExpressionForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { ProcessExpressionApi, ProcessExpressionVO } from '@/api/bpm/processExpression' -import ProcessExpressionForm from './ProcessExpressionForm.vue' - -/** BPM 娴佺▼琛ㄨ揪寮忓垪琛� */ -defineOptions({ name: 'BpmProcessExpression' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ProcessExpressionVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProcessExpressionApi.getProcessExpressionPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProcessExpressionApi.deleteProcessExpression(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/processInstance/create/index.vue b/src/views/bpm/processInstance/create/index.vue deleted file mode 100644 index cc58888..0000000 --- a/src/views/bpm/processInstance/create/index.vue +++ /dev/null @@ -1,257 +0,0 @@ -<template> - <doc-alert title="娴佺▼鍙戣捣銆佸彇娑堛�侀噸鏂板彂璧�" url="https://doc.iocoder.cn/bpm/process-instance/" /> - - <!-- 绗竴姝ワ紝閫氳繃娴佺▼瀹氫箟鐨勫垪琛紝閫夋嫨瀵瑰簲鐨勬祦绋� --> - <ContentWrap v-if="!selectProcessDefinition" v-loading="loading"> - <el-tabs tab-position="left" v-model="categoryActive"> - <el-tab-pane - :label="category.name" - :name="category.code" - :key="category.code" - v-for="category in categoryList" - > - <el-row :gutter="20"> - <el-col - :lg="6" - :sm="12" - :xs="24" - v-for="definition in categoryProcessDefinitionList" - :key="definition.id" - > - <el-card - shadow="hover" - class="mb-20px cursor-pointer" - @click="handleSelect(definition)" - > - <template #default> - <div class="flex"> - <el-image :src="definition.icon" class="w-32px h-32px" /> - <el-text class="!ml-10px" size="large">{{ definition.name }}</el-text> - </div> - </template> - </el-card> - </el-col> - </el-row> - </el-tab-pane> - </el-tabs> - </ContentWrap> - - <!-- 绗簩姝ワ紝濉啓琛ㄥ崟锛岃繘琛屾祦绋嬬殑鎻愪氦 --> - <ContentWrap v-else> - <el-card class="box-card"> - <div class="clearfix"> - <span class="el-icon-document">鐢宠淇℃伅銆恵{ selectProcessDefinition.name }}銆�</span> - <el-button style="float: right" type="primary" @click="selectProcessDefinition = undefined"> - <Icon icon="ep:delete" /> 閫夋嫨鍏跺畠娴佺▼ - </el-button> - </div> - <el-col :span="16" :offset="6" style="margin-top: 20px"> - <form-create - :rule="detailForm.rule" - v-model:api="fApi" - v-model="detailForm.value" - :option="detailForm.option" - @submit="submitForm" - > - <template #type-startUserSelect> - <el-col :span="24"> - <el-card class="mb-10px"> - <template #header>鎸囧畾瀹℃壒浜�</template> - <el-form - :model="startUserSelectAssignees" - :rules="startUserSelectAssigneesFormRules" - ref="startUserSelectAssigneesFormRef" - > - <el-form-item - v-for="userTask in startUserSelectTasks" - :key="userTask.id" - :label="`浠诲姟銆�${userTask.name}銆慲" - :prop="userTask.id" - > - <el-select - v-model="startUserSelectAssignees[userTask.id]" - multiple - placeholder="璇烽�夋嫨瀹℃壒浜�" - > - <el-option - v-for="user in userList" - :key="user.id" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - </el-form> - </el-card> - </el-col> - </template> - </form-create> - </el-col> - </el-card> - <!-- 娴佺▼鍥鹃瑙� --> - <ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML as any" /> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as DefinitionApi from '@/api/bpm/definition' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' -import { setConfAndFields2 } from '@/utils/formCreate' -import type { ApiAttrs } from '@form-create/element-ui/types/config' -import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue' -import { CategoryApi } from '@/api/bpm/category' -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'BpmProcessInstanceCreate' }) - -const route = useRoute() // 璺敱 -const { push, currentRoute } = useRouter() // 璺敱 -const message = useMessage() // 娑堟伅 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 - -const processInstanceId = route.query.processInstanceId -const loading = ref(true) // 鍔犺浇涓� -const categoryList = ref([]) // 鍒嗙被鐨勫垪琛� -const categoryActive = ref('') // 閫変腑鐨勫垎绫� -const processDefinitionList = ref([]) // 娴佺▼瀹氫箟鐨勫垪琛� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 娴佺▼鍒嗙被 - categoryList.value = await CategoryApi.getCategorySimpleList() - if (categoryList.value.length > 0) { - categoryActive.value = categoryList.value[0].code - } - // 娴佺▼瀹氫箟 - processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({ - suspensionState: 1 - }) - - // 濡傛灉 processInstanceId 闈炵┖锛岃鏄庢槸閲嶆柊鍙戣捣 - if (processInstanceId?.length > 0) { - const processInstance = await ProcessInstanceApi.getProcessInstance(processInstanceId) - if (!processInstance) { - message.error('閲嶆柊鍙戣捣娴佺▼澶辫触锛屽師鍥狅細娴佺▼瀹炰緥涓嶅瓨鍦�') - return - } - const processDefinition = processDefinitionList.value.find( - (item) => item.key == processInstance.processDefinition?.key - ) - if (!processDefinition) { - message.error('閲嶆柊鍙戣捣娴佺▼澶辫触锛屽師鍥狅細娴佺▼瀹氫箟涓嶅瓨鍦�') - return - } - await handleSelect(processDefinition, processInstance.formVariables) - } - } finally { - loading.value = false - } -} - -/** 閫変腑鍒嗙被瀵瑰簲鐨勬祦绋嬪畾涔夊垪琛� */ -const categoryProcessDefinitionList = computed(() => { - return processDefinitionList.value.filter((item) => item.category == categoryActive.value) -}) - -// ========== 琛ㄥ崟鐩稿叧 ========== -const fApi = ref<ApiAttrs>() -const detailForm = ref({ - rule: [], - option: {}, - value: {} -}) // 娴佺▼琛ㄥ崟璇︽儏 -const selectProcessDefinition = ref() // 閫夋嫨鐨勬祦绋嬪畾涔� - -// 鎸囧畾瀹℃壒浜� -const bpmnXML = ref(null) // BPMN 鏁版嵁 -const startUserSelectTasks = ref([]) // 鍙戣捣浜洪渶瑕侀�夋嫨瀹℃壒浜虹殑鐢ㄦ埛浠诲姟鍒楄〃 -const startUserSelectAssignees = ref({}) // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑鏁版嵁 -const startUserSelectAssigneesFormRef = ref() // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑琛ㄥ崟 Ref -const startUserSelectAssigneesFormRules = ref({}) // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑琛ㄥ崟 Rules -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 澶勭悊閫夋嫨娴佺▼鐨勬寜閽搷浣� **/ -const handleSelect = async (row, formVariables) => { - // 璁剧疆閫夋嫨鐨勬祦绋� - selectProcessDefinition.value = row - - // 閲嶇疆鎸囧畾瀹℃壒浜� - startUserSelectTasks.value = [] - startUserSelectAssignees.value = {} - startUserSelectAssigneesFormRules.value = {} - - // 鎯呭喌涓�锛氭祦绋嬭〃鍗� - if (row.formType == 10) { - // 璁剧疆琛ㄥ崟 - setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables) - // 鍔犺浇娴佺▼鍥� - const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id) - if (processDefinitionDetail) { - bpmnXML.value = processDefinitionDetail.bpmnXml - startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks - - // 璁剧疆鎸囧畾瀹℃壒浜� - if (startUserSelectTasks.value?.length > 0) { - detailForm.value.rule.push({ - type: 'startUserSelect', - props: { - title: '鎸囧畾瀹℃壒浜�' - } - }) - // 璁剧疆鏍¢獙瑙勫垯 - for (const userTask of startUserSelectTasks.value) { - startUserSelectAssignees.value[userTask.id] = [] - startUserSelectAssigneesFormRules.value[userTask.id] = [ - { required: true, message: '璇烽�夋嫨瀹℃壒浜�', trigger: 'blur' } - ] - } - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - } - } - // 鎯呭喌浜岋細涓氬姟琛ㄥ崟 - } else if (row.formCustomCreatePath) { - await push({ - path: row.formCustomCreatePath - }) - // 杩欓噷鏆傛椂鏃犻渶鍔犺浇娴佺▼鍥撅紝鍥犱负璺冲嚭鍒板彟澶栦釜 Tab锛� - } -} - -/** 鎻愪氦鎸夐挳 */ -const submitForm = async (formData) => { - if (!fApi.value || !selectProcessDefinition.value) { - return - } - // 濡傛灉鏈夋寚瀹氬鎵逛汉锛岄渶瑕佹牎楠� - if (startUserSelectTasks.value?.length > 0) { - await startUserSelectAssigneesFormRef.value.validate() - } - - // 鎻愪氦璇锋眰 - fApi.value.btn.loading(true) - try { - await ProcessInstanceApi.createProcessInstance({ - processDefinitionId: selectProcessDefinition.value.id, - variables: formData, - startUserSelectAssignees: startUserSelectAssignees.value - }) - // 鎻愮ず - message.success('鍙戣捣娴佺▼鎴愬姛') - // 璺宠浆鍥炲幓 - delView(unref(currentRoute)) - await push({ - name: 'BpmProcessInstanceMy' - }) - } finally { - fApi.value.btn.loading(false) - } -} - -/** 鍒濆鍖� */ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue b/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue deleted file mode 100644 index 8912593..0000000 --- a/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> - <el-card v-loading="loading" class="box-card"> - <template #header> - <span class="el-icon-picture-outline">娴佺▼鍥�</span> - </template> - <MyProcessViewer - key="designer" - :activityData="activityList" - :prefix="bpmnControlForm.prefix" - :processInstanceData="processInstance" - :taskData="tasks" - :value="bpmnXml" - v-bind="bpmnControlForm" - /> - </el-card> -</template> -<script lang="ts" setup> -import { propTypes } from '@/utils/propTypes' -import { MyProcessViewer } from '@/components/bpmnProcessDesigner/package' -import * as ActivityApi from '@/api/bpm/activity' - -defineOptions({ name: 'BpmProcessInstanceBpmnViewer' }) - -const props = defineProps({ - loading: propTypes.bool, // 鏄惁鍔犺浇涓� - id: propTypes.string, // 娴佺▼瀹炰緥鐨勭紪鍙� - processInstance: propTypes.any, // 娴佺▼瀹炰緥鐨勪俊鎭� - tasks: propTypes.array, // 娴佺▼浠诲姟鐨勬暟缁� - bpmnXml: propTypes.string // BPMN XML -}) - -const bpmnControlForm = ref({ - prefix: 'flowable' -}) -const activityList = ref([]) // 浠诲姟鍒楄〃 - -/** 鍙湁 loading 瀹屾垚鏃讹紝鎵嶅幓鍔犺浇娴佺▼鍒楄〃 */ -watch( - () => props.loading, - async (value) => { - if (value && props.id) { - activityList.value = await ActivityApi.getActivityList({ - processInstanceId: props.id - }) - } - } -) -</script> -<style> -.box-card { - width: 100%; - margin-bottom: 20px; -} -</style> diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue b/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue deleted file mode 100644 index f82e800..0000000 --- a/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue +++ /dev/null @@ -1,175 +0,0 @@ -<template> - <el-card v-loading="loading" class="box-card"> - <template #header> - <span class="el-icon-picture-outline">瀹℃壒璁板綍</span> - </template> - <el-col :offset="3" :span="17"> - <div class="block"> - <el-timeline> - <el-timeline-item - v-if="processInstance.endTime" - :type="getProcessInstanceTimelineItemType(processInstance)" - > - <p style="font-weight: 700"> - 缁撴潫娴佺▼锛氬湪 {{ formatDate(processInstance?.endTime) }} 缁撴潫 - <dict-tag - :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" - :value="processInstance.status" - /> - </p> - </el-timeline-item> - <el-timeline-item - v-for="(item, index) in tasks" - :key="index" - :type="getTaskTimelineItemType(item)" - > - <p style="font-weight: 700"> - 瀹℃壒浠诲姟锛歿{ item.name }} - <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="item.status" /> - <el-button - class="ml-10px" - v-if="!isEmpty(item.children)" - @click="openChildrenTask(item)" - size="small" - > - <Icon icon="ep:memo" /> 瀛愪换鍔� - </el-button> - <el-button - class="ml-10px" - size="small" - v-if="item.formId > 0" - @click="handleFormDetail(item)" - > - <Icon icon="ep:document" /> 鏌ョ湅琛ㄥ崟 - </el-button> - </p> - <el-card :body-style="{ padding: '10px' }"> - <label v-if="item.assigneeUser" style="margin-right: 30px; font-weight: normal"> - 瀹℃壒浜猴細{{ item.assigneeUser.nickname }} - <el-tag size="small" type="info">{{ item.assigneeUser.deptName }}</el-tag> - </label> - <label v-if="item.createTime" style="font-weight: normal">鍒涘缓鏃堕棿锛�</label> - <label style="font-weight: normal; color: #8a909c"> - {{ formatDate(item?.createTime) }} - </label> - <label v-if="item.endTime" style="margin-left: 30px; font-weight: normal"> - 瀹℃壒鏃堕棿锛� - </label> - <label v-if="item.endTime" style="font-weight: normal; color: #8a909c"> - {{ formatDate(item?.endTime) }} - </label> - <label v-if="item.durationInMillis" style="margin-left: 30px; font-weight: normal"> - 鑰楁椂锛� - </label> - <label v-if="item.durationInMillis" style="font-weight: normal; color: #8a909c"> - {{ formatPast2(item?.durationInMillis) }} - </label> - <p v-if="item.reason"> 瀹℃壒寤鸿锛歿{ item.reason }} </p> - </el-card> - </el-timeline-item> - <el-timeline-item type="success"> - <p style="font-weight: 700"> - 鍙戣捣娴佺▼锛氥�恵{ processInstance.startUser?.nickname }}銆戝湪 - {{ formatDate(processInstance?.startTime) }} 鍙戣捣銆� {{ processInstance.name }} 銆戞祦绋� - </p> - </el-timeline-item> - </el-timeline> - </div> - </el-col> - </el-card> - - <!-- 寮圭獥锛氬瓙浠诲姟 --> - <TaskSignList ref="taskSignListRef" @success="refresh" /> - <!-- 寮圭獥锛氳〃鍗� --> - <Dialog title="琛ㄥ崟璇︽儏" v-model="taskFormVisible" width="600"> - <form-create - ref="fApi" - v-model="taskForm.value" - :option="taskForm.option" - :rule="taskForm.rule" - /> - </Dialog> -</template> -<script lang="ts" setup> -import { formatDate, formatPast2 } from '@/utils/formatTime' -import { propTypes } from '@/utils/propTypes' -import { DICT_TYPE } from '@/utils/dict' -import { isEmpty } from '@/utils/is' -import TaskSignList from './dialog/TaskSignList.vue' -import type { ApiAttrs } from '@form-create/element-ui/types/config' -import { setConfAndFields2 } from '@/utils/formCreate' - -defineOptions({ name: 'BpmProcessInstanceTaskList' }) - -defineProps({ - loading: propTypes.bool, // 鏄惁鍔犺浇涓� - processInstance: propTypes.object, // 娴佺▼瀹炰緥 - tasks: propTypes.arrayOf(propTypes.object) // 娴佺▼浠诲姟鐨勬暟缁� -}) - -/** 鑾峰緱娴佺▼瀹炰緥瀵瑰簲鐨勯鑹� */ -const getProcessInstanceTimelineItemType = (item: any) => { - if (item.status === 2) { - return 'success' - } - if (item.status === 3) { - return 'danger' - } - if (item.status === 4) { - return 'warning' - } - return '' -} - -/** 鑾峰緱浠诲姟瀵瑰簲鐨勯鑹� */ -const getTaskTimelineItemType = (item: any) => { - if ([0, 1, 6, 7].includes(item.status)) { - return 'primary' - } - if (item.status === 2) { - return 'success' - } - if (item.status === 3) { - return 'danger' - } - if (item.status === 4) { - return 'info' - } - if (item.status === 5) { - return 'warning' - } - return '' -} - -/** 瀛愪换鍔� */ -const taskSignListRef = ref() -const openChildrenTask = (item: any) => { - taskSignListRef.value.open(item) -} - -/** 鏌ョ湅琛ㄥ崟 */ -const fApi = ref<ApiAttrs>() // form-create 鐨� API 鎿嶄綔绫� -const taskForm = ref({ - rule: [], - option: {}, - value: {} -}) // 娴佺▼浠诲姟鐨勮〃鍗曡鎯� -const taskFormVisible = ref(false) -const handleFormDetail = async (row) => { - // 璁剧疆琛ㄥ崟 - setConfAndFields2(taskForm, row.formConf, row.formFields, row.formVariables) - // 寮圭獥鎵撳紑 - taskFormVisible.value = true - // 闅愯棌鎻愪氦銆侀噸缃寜閽紝璁剧疆绂佺敤鍙 - await nextTick() - fApi.value.fapi.btn.show(false) - fApi.value?.fapi?.resetBtn.show(false) - fApi.value?.fapi?.disabled(true) -} - -/** 鍒锋柊鏁版嵁 */ -const emit = defineEmits(['refresh']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const refresh = () => { - emit('refresh') -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskDelegateForm.vue b/src/views/bpm/processInstance/detail/dialog/TaskDelegateForm.vue deleted file mode 100644 index 178b1b9..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskDelegateForm.vue +++ /dev/null @@ -1,89 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="濮旀淳浠诲姟" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="鎺ユ敹浜�" prop="delegateUserId"> - <el-select v-model="formData.delegateUserId" clearable style="width: 100%"> - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="濮旀淳鐞嗙敱" prop="reason"> - <el-input v-model="formData.reason" clearable placeholder="璇疯緭鍏ュ娲剧悊鐢�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TaskApi from '@/api/bpm/task' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'BpmTaskDelegateForm' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: '', - delegateUserId: undefined, - reason: '' -}) -const formRules = ref({ - delegateUserId: [{ required: true, message: '鎺ユ敹浜轰笉鑳戒负绌�', trigger: 'change' }], - reason: [{ required: true, message: '濮旀淳鐞嗙敱涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (id: string) => { - dialogVisible.value = true - resetForm() - formData.value.id = id - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await TaskApi.delegateTask(formData.value) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: '', - delegateUserId: undefined, - reason: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskReturnForm.vue b/src/views/bpm/processInstance/detail/dialog/TaskReturnForm.vue deleted file mode 100644 index a139169..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskReturnForm.vue +++ /dev/null @@ -1,90 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍥為��浠诲姟" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="閫�鍥炶妭鐐�" prop="targetTaskDefinitionKey"> - <el-select v-model="formData.targetTaskDefinitionKey" clearable style="width: 100%"> - <el-option - v-for="item in returnList" - :key="item.taskDefinitionKey" - :label="item.name" - :value="item.taskDefinitionKey" - /> - </el-select> - </el-form-item> - <el-form-item label="鍥為��鐞嗙敱" prop="reason"> - <el-input v-model="formData.reason" clearable placeholder="璇疯緭鍏ュ洖閫�鐞嗙敱" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" name="TaskRollbackDialogForm" setup> -import * as TaskApi from '@/api/bpm/task' - -const message = useMessage() // 娑堟伅寮圭獥 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: '', - targetTaskDefinitionKey: undefined, - reason: '' -}) -const formRules = ref({ - targetTaskDefinitionKey: [{ required: true, message: '蹇呴』閫夋嫨鍥為��鑺傜偣', trigger: 'change' }], - reason: [{ required: true, message: '鍥為��鐞嗙敱涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref -const returnList = ref([] as any) -/** 鎵撳紑寮圭獥 */ -const open = async (id: string) => { - returnList.value = await TaskApi.getTaskListByReturn(id) - if (returnList.value.length === 0) { - message.warning('褰撳墠娌℃湁鍙洖閫�鐨勮妭鐐�') - return false - } - dialogVisible.value = true - resetForm() - formData.value.id = id -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await TaskApi.returnTask(formData.value) - message.success('鍥為��鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: '', - targetTaskDefinitionKey: undefined, - reason: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskSignCreateForm.vue b/src/views/bpm/processInstance/detail/dialog/TaskSignCreateForm.vue deleted file mode 100644 index 9e4998c..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskSignCreateForm.vue +++ /dev/null @@ -1,99 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍔犵" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="鍔犵澶勭悊浜�" prop="userIds"> - <el-select v-model="formData.userIds" multiple clearable style="width: 100%"> - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍔犵鐞嗙敱" prop="reason"> - <el-input v-model="formData.reason" clearable placeholder="璇疯緭鍏ュ姞绛剧悊鐢�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm('before')"> - 鍚戝墠鍔犵 - </el-button> - <el-button :disabled="formLoading" type="primary" @click="submitForm('after')"> - 鍚戝悗鍔犵 - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TaskApi from '@/api/bpm/task' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'TaskSignCreateForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: '', - userIds: [], - type: '', - reason: '' -}) -const formRules = ref({ - userIds: [{ required: true, message: '鍔犵澶勭悊浜轰笉鑳戒负绌�', trigger: 'change' }], - reason: [{ required: true, message: '鍔犵鐞嗙敱涓嶈兘涓虹┖', trigger: 'change' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (id: string) => { - dialogVisible.value = true - resetForm() - formData.value.id = id - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async (type: string) => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - formData.value.type = type - try { - await TaskApi.signCreateTask(formData.value) - message.success('鍔犵鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: '', - userIds: [], - type: '', - reason: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskSignDeleteForm.vue b/src/views/bpm/processInstance/detail/dialog/TaskSignDeleteForm.vue deleted file mode 100644 index 19bb2dc..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskSignDeleteForm.vue +++ /dev/null @@ -1,89 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍑忕" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="鍑忕浠诲姟" prop="id"> - <el-radio-group v-model="formData.id"> - <el-radio-button v-for="item in childrenTaskList" :key="item.id" :label="item.id"> - {{ item.name }} - ({{ item.assigneeUser?.deptName || item.ownerUser?.deptName }} - - {{ item.assigneeUser?.nickname || item.ownerUser?.nickname }}) - </el-radio-button> - </el-radio-group> - </el-form-item> - <el-form-item label="鍑忕鐞嗙敱" prop="reason"> - <el-input v-model="formData.reason" clearable placeholder="璇疯緭鍏ュ噺绛剧悊鐢�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TaskApi from '@/api/bpm/task' -import { isEmpty } from '@/utils/is' - -defineOptions({ name: 'TaskSignDeleteForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: '', - reason: '' -}) -const formRules = ref({ - id: [{ required: true, message: '蹇呴』閫夋嫨鍑忕浠诲姟', trigger: 'change' }], - reason: [{ required: true, message: '鍑忕鐞嗙敱涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref -const childrenTaskList = ref([]) -/** 鎵撳紑寮圭獥 */ -const open = async (id: string) => { - childrenTaskList.value = await TaskApi.getChildrenTaskList(id) - if (isEmpty(childrenTaskList.value)) { - message.warning('褰撳墠娌℃湁鍙噺绛剧殑浠诲姟') - return false - } - dialogVisible.value = true - resetForm() -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await TaskApi.signDeleteTask(formData.value) - message.success('鍑忕鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: '', - reason: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskSignList.vue b/src/views/bpm/processInstance/detail/dialog/TaskSignList.vue deleted file mode 100644 index 648e86b..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskSignList.vue +++ /dev/null @@ -1,106 +0,0 @@ -<template> - <el-drawer v-model="drawerVisible" title="瀛愪换鍔�" size="880px"> - <!-- 褰撳墠浠诲姟 --> - <template #header> - <h4>銆恵{ parentTask.name }} 銆戝鎵逛汉锛歿{ parentTask?.assigneeUser?.nickname }}</h4> - <el-button - style="margin-left: 5px" - v-if="isSignDeleteButtonVisible(parentTask)" - type="danger" - plain - @click="handleSignDelete(parentTask)" - > - <Icon icon="ep:remove" /> 鍑忕 - </el-button> - </template> - <!-- 瀛愪换鍔″垪琛� --> - <el-table :data="parentTask.children" style="width: 100%" row-key="id" border> - <el-table-column prop="assigneeUser.nickname" label="瀹℃壒浜�" min-width="100"> - <template #default="scope"> - {{ scope.row.assigneeUser?.nickname || scope.row.ownerUser?.nickname }} - </template> - </el-table-column> - <el-table-column prop="assigneeUser.deptName" label="鎵�鍦ㄩ儴闂�" min-width="100"> - <template #default="scope"> - {{ scope.row.assigneeUser?.deptName || scope.row.ownerUser?.deptName }} - </template> - </el-table-column> - <el-table-column label="瀹℃壒鐘舵��" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鎻愪氦鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column - label="缁撴潫鏃堕棿" - align="center" - prop="endTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" prop="operation" width="90"> - <template #default="scope"> - <el-button - v-if="isSignDeleteButtonVisible(scope.row)" - type="danger" - plain - size="small" - @click="handleSignDelete(scope.row)" - > - <Icon icon="ep:remove" /> 鍑忕 - </el-button> - </template> - </el-table-column> - </el-table> - - <!-- 鍑忕 --> - <TaskSignDeleteForm ref="taskSignDeleteFormRef" @success="handleSignDeleteSuccess" /> - </el-drawer> -</template> -<script lang="ts" setup> -import { isEmpty } from '@/utils/is' -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import TaskSignDeleteForm from './TaskSignDeleteForm.vue' - -defineOptions({ name: 'TaskSignList' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const drawerVisible = ref(false) // 鎶藉眽鐨勬槸鍚﹀睍绀� -const parentTask = ref({} as any) - -/** 鎵撳紑寮圭獥 */ -const open = async (task: any) => { - if (isEmpty(task.children)) { - message.warning('璇ヤ换鍔℃病鏈夊瓙浠诲姟') - return - } - parentTask.value = task - // 灞曞紑鎶藉眽 - drawerVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鍙戣捣鍑忕 */ -const taskSignDeleteFormRef = ref() -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const handleSignDelete = (item: any) => { - taskSignDeleteFormRef.value.open(item.id) -} -const handleSignDeleteSuccess = () => { - emit('success') - // 鍏抽棴鎶藉眽 - drawerVisible.value = false -} - -/** 鏄惁鏄剧ず鍑忕鎸夐挳 */ -const isSignDeleteButtonVisible = (task: any) => { - return task && task.children && !isEmpty(task.children) -} -</script> diff --git a/src/views/bpm/processInstance/detail/dialog/TaskTransferForm.vue b/src/views/bpm/processInstance/detail/dialog/TaskTransferForm.vue deleted file mode 100644 index c1012ac..0000000 --- a/src/views/bpm/processInstance/detail/dialog/TaskTransferForm.vue +++ /dev/null @@ -1,89 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="杞淳浠诲姟" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-form-item label="鏂板鎵逛汉" prop="assigneeUserId"> - <el-select v-model="formData.assigneeUserId" clearable style="width: 100%"> - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="杞淳鐞嗙敱" prop="reason"> - <el-input v-model="formData.reason" clearable placeholder="璇疯緭鍏ヨ浆娲剧悊鐢�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TaskApi from '@/api/bpm/task' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'TaskTransferForm' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: '', - assigneeUserId: undefined, - reason: '' -}) -const formRules = ref({ - assigneeUserId: [{ required: true, message: '鏂板鎵逛汉涓嶈兘涓虹┖', trigger: 'change' }], - reason: [{ required: true, message: '杞淳鐞嗙敱涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (id: string) => { - dialogVisible.value = true - resetForm() - formData.value.id = id - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 openModal 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await TaskApi.transferTask(formData.value) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: '', - assigneeUserId: undefined, - reason: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processInstance/detail/index.vue b/src/views/bpm/processInstance/detail/index.vue deleted file mode 100644 index da54769..0000000 --- a/src/views/bpm/processInstance/detail/index.vue +++ /dev/null @@ -1,381 +0,0 @@ -<template> - <ContentWrap> - <!-- 瀹℃壒淇℃伅 --> - <el-card - v-for="(item, index) in runningTasks" - :key="index" - v-loading="processInstanceLoading" - class="box-card" - > - <template #header> - <span class="el-icon-picture-outline">瀹℃壒浠诲姟銆恵{ item.name }}銆�</span> - </template> - <el-col :offset="6" :span="16"> - <el-form - :ref="'form' + index" - :model="auditForms[index]" - :rules="auditRule" - label-width="100px" - > - <el-form-item v-if="processInstance && processInstance.name" label="娴佺▼鍚�"> - {{ processInstance.name }} - </el-form-item> - <el-form-item v-if="processInstance && processInstance.startUser" label="娴佺▼鍙戣捣浜�"> - {{ processInstance?.startUser.nickname }} - <el-tag size="small" type="info">{{ processInstance?.startUser.deptName }}</el-tag> - </el-form-item> - <el-card v-if="runningTasks[index].formId > 0" class="mb-15px !-mt-10px"> - <template #header> - <span class="el-icon-picture-outline"> - 濉啓琛ㄥ崟銆恵{ runningTasks[index]?.formName }}銆� - </span> - </template> - <form-create - v-model="approveForms[index].value" - v-model:api="approveFormFApis[index]" - :option="approveForms[index].option" - :rule="approveForms[index].rule" - /> - </el-card> - <el-form-item label="瀹℃壒寤鸿" prop="reason"> - <el-input - v-model="auditForms[index].reason" - placeholder="璇疯緭鍏ュ鎵瑰缓璁�" - type="textarea" - /> - </el-form-item> - <el-form-item label="鎶勯�佷汉" prop="copyUserIds"> - <el-select v-model="auditForms[index].copyUserIds" multiple placeholder="璇烽�夋嫨鎶勯�佷汉"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-form> - <div style="margin-bottom: 20px; margin-left: 10%; font-size: 14px"> - <el-button type="success" @click="handleAudit(item, true)"> - <Icon icon="ep:select" /> - 閫氳繃 - </el-button> - <el-button type="danger" @click="handleAudit(item, false)"> - <Icon icon="ep:close" /> - 涓嶉�氳繃 - </el-button> - <el-button type="primary" @click="openTaskUpdateAssigneeForm(item.id)"> - <Icon icon="ep:edit" /> - 杞姙 - </el-button> - <el-button type="primary" @click="handleDelegate(item)"> - <Icon icon="ep:position" /> - 濮旀淳 - </el-button> - <el-button type="primary" @click="handleSign(item)"> - <Icon icon="ep:plus" /> - 鍔犵 - </el-button> - <el-button type="warning" @click="handleBack(item)"> - <Icon icon="ep:back" /> - 鍥為�� - </el-button> - </div> - </el-col> - </el-card> - - <!-- 鐢宠淇℃伅 --> - <el-card v-loading="processInstanceLoading" class="box-card"> - <template #header> - <span class="el-icon-document">鐢宠淇℃伅銆恵{ processInstance.name }}銆�</span> - </template> - <!-- 鎯呭喌涓�锛氭祦绋嬭〃鍗� --> - <el-col v-if="processInstance?.processDefinition?.formType === 10" :offset="6" :span="16"> - <form-create - v-model="detailForm.value" - v-model:api="fApi" - :option="detailForm.option" - :rule="detailForm.rule" - /> - </el-col> - <!-- 鎯呭喌浜岋細涓氬姟琛ㄥ崟 --> - <div v-if="processInstance?.processDefinition?.formType === 20"> - <BusinessFormComponent :id="processInstance.businessKey" /> - </div> - </el-card> - - <!-- 瀹℃壒璁板綍 --> - <ProcessInstanceTaskList - :loading="tasksLoad" - :process-instance="processInstance" - :tasks="tasks" - @refresh="getTaskList" - /> - - <!-- 楂樹寒娴佺▼鍥� --> - <ProcessInstanceBpmnViewer - :id="`${id}`" - :bpmn-xml="bpmnXml" - :loading="processInstanceLoading" - :process-instance="processInstance" - :tasks="tasks" - /> - - <!-- 寮圭獥锛氳浆娲惧鎵逛汉 --> - <TaskTransferForm ref="taskTransferFormRef" @success="getDetail" /> - <!-- 寮圭獥锛氬洖閫�鑺傜偣 --> - <TaskReturnForm ref="taskReturnFormRef" @success="getDetail" /> - <!-- 寮圭獥锛氬娲撅紝灏嗕换鍔″娲剧粰鍒汉澶勭悊锛屽鐞嗗畬鎴愬悗锛屼細閲嶆柊鍥炲埌鍘熷鎵逛汉鎵嬩腑--> - <TaskDelegateForm ref="taskDelegateForm" @success="getDetail" /> - <!-- 寮圭獥锛氬姞绛撅紝褰撳墠浠诲姟瀹℃壒浜轰负A锛屽悜鍓嶅姞绛鹃�変簡涓�涓狢锛屽垯闇�瑕丆鍏堝鎵癸紝鐒跺悗鍐嶆槸A瀹℃壒锛屽悜鍚庡姞绛綛锛孉瀹℃壒瀹岋紝闇�瑕丅鍐嶅鎵瑰畬锛屾墠绠楀畬鎴愯繖涓换鍔¤妭鐐� --> - <TaskSignCreateForm ref="taskSignCreateFormRef" @success="getDetail" /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { useUserStore } from '@/store/modules/user' -import { setConfAndFields2 } from '@/utils/formCreate' -import type { ApiAttrs } from '@form-create/element-ui/types/config' -import * as DefinitionApi from '@/api/bpm/definition' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' -import * as TaskApi from '@/api/bpm/task' -import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue' -import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue' -import TaskReturnForm from './dialog/TaskReturnForm.vue' -import TaskDelegateForm from './dialog/TaskDelegateForm.vue' -import TaskTransferForm from './dialog/TaskTransferForm.vue' -import TaskSignCreateForm from './dialog/TaskSignCreateForm.vue' -import { registerComponent } from '@/utils/routerHelper' -import { isEmpty } from '@/utils/is' -import * as UserApi from '@/api/system/user' - -defineOptions({ name: 'BpmProcessInstanceDetail' }) - -const { query } = useRoute() // 鏌ヨ鍙傛暟 -const message = useMessage() // 娑堟伅寮圭獥 -const { proxy } = getCurrentInstance() as any - -const userId = useUserStore().getUser.id // 褰撳墠鐧诲綍鐨勭紪鍙� -const id = query.id as unknown as string // 娴佺▼瀹炰緥鐨勭紪鍙� -const processInstanceLoading = ref(false) // 娴佺▼瀹炰緥鐨勫姞杞戒腑 -const processInstance = ref<any>({}) // 娴佺▼瀹炰緥 -const bpmnXml = ref('') // BPMN XML -const tasksLoad = ref(true) // 浠诲姟鐨勫姞杞戒腑 -const tasks = ref<any[]>([]) // 浠诲姟鍒楄〃 -// ========== 瀹℃壒淇℃伅 ========== -const runningTasks = ref<any[]>([]) // 杩愯涓殑浠诲姟 -const auditForms = ref<any[]>([]) // 瀹℃壒浠诲姟鐨勮〃鍗� -const auditRule = reactive({ - reason: [{ required: true, message: '瀹℃壒寤鸿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const approveForms = ref<any[]>([]) // 瀹℃壒閫氳繃鏃讹紝棰濆鐨勮ˉ鍏呬俊鎭� -const approveFormFApis = ref<ApiAttrs[]>([]) // approveForms 鐨� fAPi - -// ========== 鐢宠淇℃伅 ========== -const fApi = ref<ApiAttrs>() // -const detailForm = ref({ - rule: [], - option: {}, - value: {} -}) // 娴佺▼瀹炰緥鐨勮〃鍗曡鎯� - -/** 鐩戝惉 approveFormFApis锛屽疄鐜板畠瀵瑰簲鐨� form-create 鍒濆鍖栧悗锛岄殣钘忔帀瀵瑰簲鐨勮〃鍗曟彁浜ゆ寜閽� */ -watch( - () => approveFormFApis.value, - (value) => { - value?.forEach((api) => { - api.btn.show(false) - api.resetBtn.show(false) - }) - }, - { - deep: true - } -) - -/** 澶勭悊瀹℃壒閫氳繃鍜屼笉閫氳繃鐨勬搷浣� */ -const handleAudit = async (task, pass) => { - // 1.1 鑾峰緱瀵瑰簲琛ㄥ崟 - const index = runningTasks.value.indexOf(task) - const auditFormRef = proxy.$refs['form' + index][0] - // 1.2 鏍¢獙琛ㄥ崟 - const elForm = unref(auditFormRef) - if (!elForm) return - const valid = await elForm.validate() - if (!valid) return - - // 2.1 鎻愪氦瀹℃壒 - const data = { - id: task.id, - reason: auditForms.value[index].reason, - copyUserIds: auditForms.value[index].copyUserIds - } - if (pass) { - // 瀹℃壒閫氳繃锛屽苟涓旀湁棰濆鐨� approveForm 琛ㄥ崟锛岄渶瑕佹牎楠� + 鎷兼帴鍒� data 琛ㄥ崟閲屾彁浜� - const formCreateApi = approveFormFApis.value[index] - if (formCreateApi) { - await formCreateApi.validate() - data.variables = approveForms.value[index].value - } - await TaskApi.approveTask(data) - message.success('瀹℃壒閫氳繃鎴愬姛') - } else { - await TaskApi.rejectTask(data) - message.success('瀹℃壒涓嶉�氳繃鎴愬姛') - } - // 2.2 鍔犺浇鏈�鏂版暟鎹� - getDetail() -} - -/** 杞淳瀹℃壒浜� */ -const taskTransferFormRef = ref() -const openTaskUpdateAssigneeForm = (id: string) => { - taskTransferFormRef.value.open(id) -} - -/** 澶勭悊瀹℃壒閫�鍥炵殑鎿嶄綔 */ -const taskDelegateForm = ref() -const handleDelegate = async (task) => { - taskDelegateForm.value.open(task.id) -} - -/** 澶勭悊瀹℃壒閫�鍥炵殑鎿嶄綔 */ -const taskReturnFormRef = ref() -const handleBack = async (task: any) => { - taskReturnFormRef.value.open(task.id) -} - -/** 澶勭悊瀹℃壒鍔犵鐨勬搷浣� */ -const taskSignCreateFormRef = ref() -const handleSign = async (task: any) => { - taskSignCreateFormRef.value.open(task.id) -} - -/** 鑾峰緱璇︽儏 */ -const getDetail = () => { - // 1. 鑾峰緱娴佺▼瀹炰緥鐩稿叧 - getProcessInstance() - // 2. 鑾峰緱娴佺▼浠诲姟鍒楄〃锛堝鎵硅褰曪級 - getTaskList() -} - -/** 鍔犺浇娴佺▼瀹炰緥 */ -const BusinessFormComponent = ref(null) // 寮傛缁勪欢 -const getProcessInstance = async () => { - try { - processInstanceLoading.value = true - const data = await ProcessInstanceApi.getProcessInstance(id) - if (!data) { - message.error('鏌ヨ涓嶅埌娴佺▼淇℃伅锛�') - return - } - processInstance.value = data - - // 璁剧疆琛ㄥ崟淇℃伅 - const processDefinition = data.processDefinition - if (processDefinition.formType === 10) { - setConfAndFields2( - detailForm, - processDefinition.formConf, - processDefinition.formFields, - data.formVariables - ) - nextTick().then(() => { - fApi.value?.btn.show(false) - fApi.value?.resetBtn.show(false) - fApi.value?.disabled(true) - }) - } else { - // 娉ㄦ剰锛歞ata.processDefinition.formCustomViewPath 鏄粍浠剁殑鍏ㄨ矾寰勶紝渚嬪璇达細/crm/contract/detail/index.vue - BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath) - } - - // 鍔犺浇娴佺▼鍥� - bpmnXml.value = ( - await DefinitionApi.getProcessDefinition(processDefinition.id as number) - )?.bpmnXml - } finally { - processInstanceLoading.value = false - } -} - -/** 鍔犺浇浠诲姟鍒楄〃 */ -const getTaskList = async () => { - runningTasks.value = [] - auditForms.value = [] - approveForms.value = [] - approveFormFApis.value = [] - try { - // 鑾峰緱鏈彇娑堢殑浠诲姟 - tasksLoad.value = true - const data = await TaskApi.getTaskListByProcessInstanceId(id) - tasks.value = [] - // 1.1 绉婚櫎宸插彇娑堢殑瀹℃壒 - data.forEach((task) => { - if (task.status !== 4) { - tasks.value.push(task) - } - }) - // 1.2 鎺掑簭锛屽皢鏈畬鎴愮殑鎺掑湪鍓嶉潰锛屽凡瀹屾垚鐨勬帓鍦ㄥ悗闈紱 - tasks.value.sort((a, b) => { - // 鏈夊凡瀹屾垚鐨勬儏鍐碉紝鎸夌収瀹屾垚鏃堕棿鍊掑簭 - if (a.endTime && b.endTime) { - return b.endTime - a.endTime - } else if (a.endTime) { - return 1 - } else if (b.endTime) { - return -1 - // 閮芥槸鏈畬鎴愶紝鎸夌収鍒涘缓鏃堕棿鍊掑簭 - } else { - return b.createTime - a.createTime - } - }) - - // 鑾峰緱闇�瑕佽嚜宸卞鎵圭殑浠诲姟 - loadRunningTask(tasks.value) - } finally { - tasksLoad.value = false - } -} - -/** - * 璁剧疆 runningTasks 涓殑浠诲姟 - */ -const loadRunningTask = (tasks) => { - tasks.forEach((task) => { - if (!isEmpty(task.children)) { - loadRunningTask(task.children) - } - // 2.1 鍙湁寰呭鐞嗘墠闇�瑕� - if (task.status !== 1 && task.status !== 6) { - return - } - // 2.2 鑷繁涓嶆槸澶勭悊浜� - if (!task.assigneeUser || task.assigneeUser.id !== userId) { - return - } - // 2.3 娣诲姞鍒板鐞嗕换鍔� - runningTasks.value.push({ ...task }) - auditForms.value.push({ - reason: '', - copyUserIds: [] - }) - - // 2.4 澶勭悊 approve 琛ㄥ崟 - if (task.formId && task.formConf) { - const approveForm = {} - setConfAndFields2(approveForm, task.formConf, task.formFields, task.formVariables) - approveForms.value.push(approveForm) - } else { - approveForms.value.push({}) // 鍗犱綅锛岄伩鍏嶄负绌� - } - }) -} - -/** 鍒濆鍖� */ -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -onMounted(async () => { - getDetail() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/bpm/processInstance/index.vue b/src/views/bpm/processInstance/index.vue deleted file mode 100644 index f1d6ca7..0000000 --- a/src/views/bpm/processInstance/index.vue +++ /dev/null @@ -1,274 +0,0 @@ -<template> - <doc-alert title="娴佺▼鍙戣捣銆佸彇娑堛�侀噸鏂板彂璧�" url="https://doc.iocoder.cn/bpm/process-instance/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎵�灞炴祦绋�" prop="processDefinitionId"> - <el-input - v-model="queryParams.processDefinitionId" - placeholder="璇疯緭鍏ユ祦绋嬪畾涔夌殑缂栧彿" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娴佺▼鍒嗙被" prop="category"> - <el-select - v-model="queryParams.category" - placeholder="璇烽�夋嫨娴佺▼鍒嗙被" - clearable - class="!w-240px" - > - <el-option - v-for="category in categoryList" - :key="category.code" - :label="category.name" - :value="category.code" - /> - </el-select> - </el-form-item> - <el-form-item label="娴佺▼鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娴佺▼鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍙戣捣鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - v-hasPermi="['bpm:process-instance:query']" - @click="handleCreate(undefined)" - > - <Icon icon="ep:plus" class="mr-5px" /> 鍙戣捣娴佺▼ - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="娴佺▼鍚嶇О" align="center" prop="name" min-width="200px" fixed="left" /> - <el-table-column - label="娴佺▼鍒嗙被" - align="center" - prop="categoryName" - min-width="100" - fixed="left" - /> - <el-table-column label="娴佺▼鐘舵��" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍙戣捣鏃堕棿" - align="center" - prop="startTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column - label="缁撴潫鏃堕棿" - align="center" - prop="endTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column align="center" label="鑰楁椂" prop="durationInMillis" width="160"> - <template #default="scope"> - {{ scope.row.durationInMillis > 0 ? formatPast2(scope.row.durationInMillis) : '-' }} - </template> - </el-table-column> - <el-table-column label="褰撳墠瀹℃壒浠诲姟" align="center" prop="tasks" min-width="120px"> - <template #default="scope"> - <el-button type="primary" v-for="task in scope.row.tasks" :key="task.id" link> - <span>{{ task.name }}</span> - </el-button> - </template> - </el-table-column> - <el-table-column label="娴佺▼缂栧彿" align="center" prop="id" min-width="320px" /> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="180"> - <template #default="scope"> - <el-button - link - type="primary" - v-hasPermi="['bpm:process-instance:cancel']" - @click="handleDetail(scope.row)" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - v-if="scope.row.status === 1" - v-hasPermi="['bpm:process-instance:query']" - @click="handleCancel(scope.row)" - > - 鍙栨秷 - </el-button> - <el-button link type="primary" v-else @click="handleCreate(scope.row)"> - 閲嶆柊鍙戣捣 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter, formatPast2 } from '@/utils/formatTime' -import { ElMessageBox } from 'element-plus' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' -import { CategoryApi } from '@/api/bpm/category' -import { ProcessInstanceVO } from '@/api/bpm/processInstance' -import * as DefinitionApi from '@/api/bpm/definition' - -defineOptions({ name: 'BpmProcessInstanceMy' }) - -const router = useRouter() // 璺敱 -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: '', - processDefinitionId: undefined, - category: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const categoryList = ref([]) // 娴佺▼鍒嗙被鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProcessInstanceApi.getProcessInstanceMyPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍙戣捣娴佺▼鎿嶄綔 **/ -const handleCreate = async (row?: ProcessInstanceVO) => { - // 濡傛灉鏄�愪笟鍔¤〃鍗曘�戯紝涓嶆敮鎸侀噸鏂板彂璧� - if (row?.id) { - const processDefinitionDetail = await DefinitionApi.getProcessDefinition( - row.processDefinitionId - ) - debugger - if (processDefinitionDetail.formType === 20) { - message.error('閲嶆柊鍙戣捣娴佺▼澶辫触锛屽師鍥狅細璇ユ祦绋嬩娇鐢ㄤ笟鍔¤〃鍗曪紝涓嶆敮鎸侀噸鏂板彂璧�') - return - } - } - // 璺宠浆鍙戣捣娴佺▼鐣岄潰 - await router.push({ - name: 'BpmProcessInstanceCreate', - query: { processInstanceId: row?.id } - }) -} - -/** 鏌ョ湅璇︽儏 */ -const handleDetail = (row) => { - router.push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.id - } - }) -} - -/** 鍙栨秷鎸夐挳鎿嶄綔 */ -const handleCancel = async (row) => { - // 浜屾纭 - const { value } = await ElMessageBox.prompt('璇疯緭鍏ュ彇娑堝師鍥�', '鍙栨秷娴佺▼', { - confirmButtonText: t('common.ok'), - cancelButtonText: t('common.cancel'), - inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 鍒ゆ柇闈炵┖锛屼笖闈炵┖鏍� - inputErrorMessage: '鍙栨秷鍘熷洜涓嶈兘涓虹┖' - }) - // 鍙戣捣鍙栨秷 - await ProcessInstanceApi.cancelProcessInstanceByStartUser(row.id, value) - message.success('鍙栨秷鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() -} - -/** 婵�娲绘椂 **/ -onActivated(() => { - getList() -}) - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - categoryList.value = await CategoryApi.getCategorySimpleList() -}) -</script> diff --git a/src/views/bpm/processInstance/manager/index.vue b/src/views/bpm/processInstance/manager/index.vue deleted file mode 100644 index ab8da9c..0000000 --- a/src/views/bpm/processInstance/manager/index.vue +++ /dev/null @@ -1,255 +0,0 @@ -<template> - <doc-alert title="宸ヤ綔娴佹墜鍐�" url="https://doc.iocoder.cn/bpm/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍙戣捣浜�" prop="startUserId"> - <el-select v-model="queryParams.startUserId" placeholder="璇烽�夋嫨鍙戣捣浜�" class="!w-240px"> - <el-option - v-for="user in userList" - :key="user.id" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎵�灞炴祦绋�" prop="processDefinitionId"> - <el-input - v-model="queryParams.processDefinitionId" - placeholder="璇疯緭鍏ユ祦绋嬪畾涔夌殑缂栧彿" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娴佺▼鍒嗙被" prop="category"> - <el-select - v-model="queryParams.category" - placeholder="璇烽�夋嫨娴佺▼鍒嗙被" - clearable - class="!w-240px" - > - <el-option - v-for="category in categoryList" - :key="category.code" - :label="category.name" - :value="category.code" - /> - </el-select> - </el-form-item> - <el-form-item label="娴佺▼鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娴佺▼鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍙戣捣鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="娴佺▼鍚嶇О" align="center" prop="name" min-width="200px" fixed="left" /> - <el-table-column - label="娴佺▼鍒嗙被" - align="center" - prop="categoryName" - min-width="100" - fixed="left" - /> - <el-table-column label="娴佺▼鍙戣捣浜�" align="center" prop="startUser.nickname" width="120" /> - <el-table-column label="鍙戣捣閮ㄩ棬" align="center" prop="startUser.deptName" width="120" /> - <el-table-column label="娴佺▼鐘舵��" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍙戣捣鏃堕棿" - align="center" - prop="startTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column - label="缁撴潫鏃堕棿" - align="center" - prop="endTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column align="center" label="鑰楁椂" prop="durationInMillis" width="169"> - <template #default="scope"> - {{ scope.row.durationInMillis > 0 ? formatPast2(scope.row.durationInMillis) : '-' }} - </template> - </el-table-column> - <el-table-column label="褰撳墠瀹℃壒浠诲姟" align="center" prop="tasks" min-width="120px"> - <template #default="scope"> - <el-button type="primary" v-for="task in scope.row.tasks" :key="task.id" link> - <span>{{ task.name }}</span> - </el-button> - </template> - </el-table-column> - <el-table-column label="娴佺▼缂栧彿" align="center" prop="id" min-width="320px" /> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="180"> - <template #default="scope"> - <el-button - link - type="primary" - v-hasPermi="['bpm:process-instance:cancel']" - @click="handleDetail(scope.row)" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - v-if="scope.row.status === 1" - v-hasPermi="['bpm:process-instance:query']" - @click="handleCancel(scope.row)" - > - 鍙栨秷 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter, formatPast2 } from '@/utils/formatTime' -import { ElMessageBox } from 'element-plus' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' -import { CategoryApi } from '@/api/bpm/category' -import * as UserApi from '@/api/system/user' -import { cancelProcessInstanceByAdmin } from '@/api/bpm/processInstance' - -// 瀹冨拰銆愭垜鐨勬祦绋嬨�戠殑宸紓鏄紝璇ヨ彍鍗曞彲浠ョ湅鍏ㄩ儴鐨勬祦绋嬪疄渚� -defineOptions({ name: 'BpmProcessInstanceManager' }) - -const router = useRouter() // 璺敱 -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - startUserId: undefined, - name: '', - processDefinitionId: undefined, - category: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const categoryList = ref([]) // 娴佺▼鍒嗙被鍒楄〃 -const userList = ref<any[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProcessInstanceApi.getProcessInstanceManagerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鏌ョ湅璇︽儏 */ -const handleDetail = (row) => { - router.push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.id - } - }) -} - -/** 鍙栨秷鎸夐挳鎿嶄綔 */ -const handleCancel = async (row) => { - // 浜屾纭 - const { value } = await ElMessageBox.prompt('璇疯緭鍏ュ彇娑堝師鍥�', '鍙栨秷娴佺▼', { - confirmButtonText: t('common.ok'), - cancelButtonText: t('common.cancel'), - inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 鍒ゆ柇闈炵┖锛屼笖闈炵┖鏍� - inputErrorMessage: '鍙栨秷鍘熷洜涓嶈兘涓虹┖' - }) - // 鍙戣捣鍙栨秷 - await ProcessInstanceApi.cancelProcessInstanceByAdmin(row.id, value) - message.success('鍙栨秷鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() -} - -/** 婵�娲绘椂 **/ -onActivated(() => { - getList() -}) - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - categoryList.value = await CategoryApi.getCategorySimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/bpm/processListener/ProcessListenerForm.vue b/src/views/bpm/processListener/ProcessListenerForm.vue deleted file mode 100644 index 8d4e979..0000000 --- a/src/views/bpm/processListener/ProcessListenerForm.vue +++ /dev/null @@ -1,162 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="110px" - v-loading="formLoading" - > - <el-form-item label="鍚嶅瓧" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕瀛�" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="绫诲瀷" prop="type"> - <el-select - v-model="formData.type" - placeholder="璇烽�夋嫨绫诲瀷" - @change="formData.event = undefined" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.BPM_PROCESS_LISTENER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="浜嬩欢" prop="event"> - <el-select v-model="formData.event" placeholder="璇烽�夋嫨浜嬩欢"> - <el-option - v-for="event in formData.type == 'execution' - ? ['start', 'end'] - : ['create', 'assignment', 'complete', 'delete', 'update', 'timeout']" - :label="event" - :value="event" - :key="event" - /> - </el-select> - </el-form-item> - <el-form-item label="鍊肩被鍨�" prop="valueType"> - <el-select v-model="formData.valueType" placeholder="璇烽�夋嫨鍊肩被鍨�"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.BPM_PROCESS_LISTENER_VALUE_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="绫昏矾寰�" prop="value" v-if="formData.type == 'class'"> - <el-input v-model="formData.value" placeholder="璇疯緭鍏ョ被璺緞" /> - </el-form-item> - <el-form-item label="琛ㄨ揪寮�" prop="value" v-else> - <el-input v-model="formData.value" placeholder="璇疯緭鍏ヨ〃杈惧紡" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict' -import { ProcessListenerApi, ProcessListenerVO } from '@/api/bpm/processListener' -import { CommonStatusEnum } from '@/utils/constants' - -/** BPM 娴佺▼ 琛ㄥ崟 */ -defineOptions({ name: 'ProcessListenerForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - type: undefined, - status: undefined, - event: undefined, - valueType: undefined, - value: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶅瓧涓嶈兘涓虹┖', trigger: 'blur' }], - type: [{ required: true, message: '绫诲瀷涓嶈兘涓虹┖', trigger: 'change' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - event: [{ required: true, message: '鐩戝惉浜嬩欢涓嶈兘涓虹┖', trigger: 'blur' }], - valueType: [{ required: true, message: '鍊肩被鍨嬩笉鑳戒负绌�', trigger: 'change' }], - value: [{ required: true, message: '鍊间笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProcessListenerApi.getProcessListener(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProcessListenerVO - if (formType.value === 'create') { - await ProcessListenerApi.createProcessListener(data) - message.success(t('common.createSuccess')) - } else { - await ProcessListenerApi.updateProcessListener(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - type: undefined, - status: CommonStatusEnum.ENABLE, - event: undefined, - valueType: undefined, - value: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/bpm/processListener/index.vue b/src/views/bpm/processListener/index.vue deleted file mode 100644 index 8b5c36e..0000000 --- a/src/views/bpm/processListener/index.vue +++ /dev/null @@ -1,185 +0,0 @@ -<template> - <doc-alert title="鎵ц鐩戝惉鍣ㄣ�佷换鍔$洃鍚櫒" url="https://doc.iocoder.cn/bpm/listener/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="85px" - > - <el-form-item label="鍚嶅瓧" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕瀛�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绫诲瀷" prop="type"> - <el-select v-model="queryParams.type" placeholder="璇烽�夋嫨绫诲瀷" clearable class="!w-240px"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.BPM_PROCESS_LISTENER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['bpm:process-listener:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="鍚嶅瓧" align="center" prop="name" /> - <el-table-column label="绫诲瀷" align="center" prop="type"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_PROCESS_LISTENER_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="浜嬩欢" align="center" prop="event" /> - <el-table-column label="鍊肩被鍨�" align="center" prop="valueType"> - <template #default="scope"> - <dict-tag - :type="DICT_TYPE.BPM_PROCESS_LISTENER_VALUE_TYPE" - :value="scope.row.valueType" - /> - </template> - </el-table-column> - <el-table-column label="鍊�" align="center" prop="value" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['bpm:process-listener:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['bpm:process-listener:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProcessListenerForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getStrDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { ProcessListenerApi, ProcessListenerVO } from '@/api/bpm/processListener' -import ProcessListenerForm from './ProcessListenerForm.vue' - -/** BPM 娴佺▼ 鍒楄〃 */ -defineOptions({ name: 'BpmProcessListener' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ProcessListenerVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - type: undefined, - event: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProcessListenerApi.getProcessListenerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProcessListenerApi.deleteProcessListener(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/simpleWorkflow/index.vue b/src/views/bpm/simpleWorkflow/index.vue deleted file mode 100644 index 144615e..0000000 --- a/src/views/bpm/simpleWorkflow/index.vue +++ /dev/null @@ -1,28 +0,0 @@ -<template> - <div> - <section class="dingflow-design"> - <div class="box-scale"> - <nodeWrap v-model:nodeConfig="nodeConfig" /> - <div class="end-node"> - <div class="end-node-circle"></div> - <div class="end-node-text">娴佺▼缁撴潫</div> - </div> - </div> - </section> - </div> -</template> -<script lang="ts" setup> -import nodeWrap from '@/components/SimpleProcessDesigner/src/nodeWrap.vue' -defineOptions({ name: 'SimpleWorkflowDesignEditor' }) -let nodeConfig = ref({ - nodeName: '鍙戣捣浜�', - type: 0, - id: 'root', - formPerms: {}, - nodeUserList: [], - childNode: {} -}) -</script> -<style> -@import url('@/components/SimpleProcessDesigner/theme/workflow.css'); -</style> \ No newline at end of file diff --git a/src/views/bpm/task/copy/index.vue b/src/views/bpm/task/copy/index.vue deleted file mode 100644 index adc1fe3..0000000 --- a/src/views/bpm/task/copy/index.vue +++ /dev/null @@ -1,137 +0,0 @@ -<!-- 宸ヤ綔娴� - 鎶勯�佹垜鐨勬祦绋� --> -<template> - <doc-alert - title="瀹℃壒杞姙銆佸娲俱�佹妱閫�" - url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form ref="queryFormRef" :inline="true" class="-mb-15px" label-width="68px"> - <el-form-item label="娴佺▼鍚嶇О" prop="name"> - <el-input - v-model="queryParams.processInstanceName" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" - /> - </el-form-item> - <el-form-item label="鎶勯�佹椂闂�" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="娴佺▼鍚�" prop="processInstanceName" min-width="180" /> - <el-table-column align="center" label="娴佺▼鍙戣捣浜�" prop="startUserName" min-width="100" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="娴佺▼鍙戣捣鏃堕棿" - prop="processInstanceStartTime" - width="180" - /> - <el-table-column align="center" label="鎶勯�佷换鍔�" prop="taskName" min-width="180" /> - <el-table-column align="center" label="鎶勯�佷汉" prop="creatorName" min-width="100" /> - <el-table-column - align="center" - label="鎶勯�佹椂闂�" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column align="center" label="鎿嶄綔" fixed="right" width="80"> - <template #default="scope"> - <el-button link type="primary" @click="handleAudit(scope.row)">璇︽儏</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as ProcessInstanceApi from '@/api/bpm/processInstance' - -defineOptions({ name: 'BpmProcessInstanceCopy' }) - -const { push } = useRouter() // 璺敱 - -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - processInstanceId: '', - processInstanceName: '', - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ浠诲姟鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProcessInstanceApi.getProcessInstanceCopyPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 澶勭悊瀹℃壒鎸夐挳 */ -const handleAudit = (row: any) => { - push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.processInstanceId - } - }) -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/task/done/index.vue b/src/views/bpm/task/done/index.vue deleted file mode 100644 index a513719..0000000 --- a/src/views/bpm/task/done/index.vue +++ /dev/null @@ -1,170 +0,0 @@ -<template> - <doc-alert title="瀹℃壒閫氳繃銆佷笉閫氳繃銆侀┏鍥�" url="https://doc.iocoder.cn/bpm/task-todo-done/" /> - <doc-alert title="瀹℃壒鍔犵銆佸噺绛�" url="https://doc.iocoder.cn/bpm/sign/" /> - <doc-alert - title="瀹℃壒杞姙銆佸娲俱�佹妱閫�" - url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/" - /> - <doc-alert title="瀹℃壒鍔犵銆佸噺绛�" url="https://doc.iocoder.cn/bpm/sign/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="浠诲姟鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヤ换鍔″悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="娴佺▼" prop="processInstance.name" width="180" /> - <el-table-column - align="center" - label="鍙戣捣浜�" - prop="processInstance.startUser.nickname" - width="100" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙戣捣鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="褰撳墠浠诲姟" prop="name" width="180" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="浠诲姟寮�濮嬫椂闂�" - prop="createTime" - width="180" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="浠诲姟缁撴潫鏃堕棿" - prop="endTime" - width="180" - /> - <el-table-column align="center" label="瀹℃壒鐘舵��" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹℃壒寤鸿" prop="reason" min-width="180" /> - <el-table-column align="center" label="鑰楁椂" prop="durationInMillis" width="160"> - <template #default="scope"> - {{ formatPast2(scope.row.durationInMillis) }} - </template> - </el-table-column> - <el-table-column align="center" label="娴佺▼缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="浠诲姟缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="鎿嶄綔" fixed="right" width="80"> - <template #default="scope"> - <el-button link type="primary" @click="handleAudit(scope.row)">鍘嗗彶</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, formatPast2 } from '@/utils/formatTime' -import * as TaskApi from '@/api/bpm/task' - -defineOptions({ name: 'BpmTodoTask' }) - -const { push } = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: '', - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ浠诲姟鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TaskApi.getTaskDonePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 澶勭悊瀹℃壒鎸夐挳 */ -const handleAudit = (row: any) => { - push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.processInstance.id - } - }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/task/manager/index.vue b/src/views/bpm/task/manager/index.vue deleted file mode 100644 index 688e515..0000000 --- a/src/views/bpm/task/manager/index.vue +++ /dev/null @@ -1,166 +0,0 @@ -<template> - <doc-alert title="宸ヤ綔娴佹墜鍐�" url="https://doc.iocoder.cn/bpm/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="浠诲姟鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヤ换鍔″悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="娴佺▼" prop="processInstance.name" width="180" /> - <el-table-column - align="center" - label="鍙戣捣浜�" - prop="processInstance.startUser.nickname" - width="100" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙戣捣鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="褰撳墠浠诲姟" prop="name" width="180" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="浠诲姟寮�濮嬫椂闂�" - prop="createTime" - width="180" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="浠诲姟缁撴潫鏃堕棿" - prop="endTime" - width="180" - /> - <el-table-column align="center" label="瀹℃壒浜�" prop="assigneeUser.nickname" width="100" /> - <el-table-column align="center" label="瀹℃壒鐘舵��" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹℃壒寤鸿" prop="reason" min-width="180" /> - <el-table-column align="center" label="鑰楁椂" prop="durationInMillis" width="160"> - <template #default="scope"> - {{ formatPast2(scope.row.durationInMillis) }} - </template> - </el-table-column> - <el-table-column align="center" label="娴佺▼缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="浠诲姟缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="鎿嶄綔" fixed="right" width="80"> - <template #default="scope"> - <el-button link type="primary" @click="handleAudit(scope.row)">鍘嗗彶</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, formatPast2 } from '@/utils/formatTime' -import * as TaskApi from '@/api/bpm/task' - -// 瀹冨拰銆愬緟鍔炰换鍔°�戙�愬凡鍔炰换鍔°�戠殑宸紓鏄紝璇ヨ彍鍗曞彲浠ョ湅鍏ㄩ儴鐨勬祦绋嬩换鍔� -defineOptions({ name: 'BpmManagerTask' }) - -const { push } = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: '', - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ浠诲姟鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TaskApi.getTaskManagerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 澶勭悊瀹℃壒鎸夐挳 */ -const handleAudit = (row: any) => { - push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.processInstance.id - } - }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/bpm/task/todo/index.vue b/src/views/bpm/task/todo/index.vue deleted file mode 100644 index 670fc68..0000000 --- a/src/views/bpm/task/todo/index.vue +++ /dev/null @@ -1,152 +0,0 @@ -<template> - <doc-alert title="瀹℃壒閫氳繃銆佷笉閫氳繃銆侀┏鍥�" url="https://doc.iocoder.cn/bpm/task-todo-done/" /> - <doc-alert title="瀹℃壒鍔犵銆佸噺绛�" url="https://doc.iocoder.cn/bpm/sign/" /> - <doc-alert - title="瀹℃壒杞姙銆佸娲俱�佹妱閫�" - url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/" - /> - <doc-alert title="瀹℃壒鍔犵銆佸噺绛�" url="https://doc.iocoder.cn/bpm/sign/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="浠诲姟鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヤ换鍔″悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="娴佺▼" prop="processInstance.name" width="180" /> - <el-table-column - align="center" - label="鍙戣捣浜�" - prop="processInstance.startUser.nickname" - width="100" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙戣捣鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="褰撳墠浠诲姟" prop="name" width="180" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="浠诲姟鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="娴佺▼缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="浠诲姟缂栧彿" prop="id" :show-overflow-tooltip="true" /> - <el-table-column align="center" label="鎿嶄綔" fixed="right" width="80"> - <template #default="scope"> - <el-button link type="primary" @click="handleAudit(scope.row)">鍔炵悊</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as TaskApi from '@/api/bpm/task' - -defineOptions({ name: 'BpmTodoTask' }) - -const { push } = useRouter() // 璺敱 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: '', - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ浠诲姟鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TaskApi.getTaskTodoPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 澶勭悊瀹℃壒鎸夐挳 */ -const handleAudit = (row: any) => { - push({ - name: 'BpmProcessInstanceDetail', - query: { - id: row.processInstance.id - } - }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/backlog/components/ClueFollowList.vue b/src/views/crm/backlog/components/ClueFollowList.vue deleted file mode 100644 index 4ed37d4..0000000 --- a/src/views/crm/backlog/components/ClueFollowList.vue +++ /dev/null @@ -1,153 +0,0 @@ -<template> - <ContentWrap> - <div class="pb-5 text-xl">鍒嗛厤缁欐垜鐨勭嚎绱�</div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鐘舵��" prop="followUpStatus"> - <el-select - v-model="queryParams.followUpStatus" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in FOLLOWUP_STATUS" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="绾跨储鍚嶇О" align="center" prop="name" fixed="left" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column label="绾跨储鏉ユ簮" align="center" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - label="鏈�鍚庤窡杩涙椂闂�" - align="center" - prop="contactLastTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100" /> - <el-table-column - label="鏇存柊鏃堕棿" - align="center" - prop="updateTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ClueApi from '@/api/crm/clue' -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { FOLLOWUP_STATUS } from './common' - -defineOptions({ name: 'CrmClueFollowList' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - followUpStatus: false, - transformStatus: false -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ClueApi.getCluePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鎵撳紑绾跨储璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmClueDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/backlog/components/ContractAuditList.vue b/src/views/crm/backlog/components/ContractAuditList.vue deleted file mode 100644 index 9c13237..0000000 --- a/src/views/crm/backlog/components/ContractAuditList.vue +++ /dev/null @@ -1,247 +0,0 @@ -<!-- 寰呭鏍稿悎鍚� --> -<template> - <ContentWrap> - <div class="pb-5 text-xl">寰呭鏍稿悎鍚�</div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍚堝悓鐘舵��" prop="auditStatus"> - <el-select - v-model="queryParams.auditStatus" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in AUDIT_STATUS" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鍚堝悓缂栧彿" prop="no" width="180" /> - <el-table-column align="center" fixed="left" label="鍚堝悓鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍟嗘満鍚嶇О" prop="businessName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openBusinessDetail(scope.row.businessId)" - > - {{ scope.row.businessName }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="鍚堝悓閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="涓嬪崟鏃堕棿" - prop="orderDate" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓寮�濮嬫椂闂�" - prop="startTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓缁撴潫鏃堕棿" - prop="endTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column align="center" label="瀹㈡埛绛剧害浜�" prop="contactName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openContactDetail(scope.row.signContactId)" - > - {{ scope.row.signContactName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍏徃绛剧害浜�" prop="signUserName" width="130" /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - align="center" - label="宸插洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="鏈洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - > - <template #default="scope"> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.totalReceivablePrice) }} - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鍚堝悓鐘舵��" prop="auditStatus" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - <el-table-column fixed="right" label="鎿嶄綔" width="90"> - <template #default="scope"> - <el-button - link - v-hasPermi="['crm:contract:update']" - type="primary" - @click="handleProcessDetail(scope.row)" - > - 鏌ョ湅瀹℃壒 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts" name="CheckContract"> -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import * as ContractApi from '@/api/crm/contract' -import { DICT_TYPE } from '@/utils/dict' -import { AUDIT_STATUS } from './common' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: 1, // 鎴戣礋璐g殑 - auditStatus: 10 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ContractApi.getContractPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鏌ョ湅瀹℃壒 */ -const handleProcessDetail = (row: ContractApi.ContractVO) => { - push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }) -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const openContactDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑鍟嗘満璇︽儏 */ -const openBusinessDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> - -<style scoped></style> diff --git a/src/views/crm/backlog/components/ContractRemindList.vue b/src/views/crm/backlog/components/ContractRemindList.vue deleted file mode 100644 index 0cacf35..0000000 --- a/src/views/crm/backlog/components/ContractRemindList.vue +++ /dev/null @@ -1,246 +0,0 @@ -<!-- 鍗冲皢鍒版湡鐨勫悎鍚� --> -<template> - <ContentWrap> - <div class="pb-5 text-xl"> 鍗冲皢鍒版湡鐨勫悎鍚� </div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍒版湡鐘舵��" prop="expiryType"> - <el-select - v-model="queryParams.expiryType" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in CONTRACT_EXPIRY_TYPE" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鍚堝悓缂栧彿" prop="no" width="180" /> - <el-table-column align="center" fixed="left" label="鍚堝悓鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍟嗘満鍚嶇О" prop="businessName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openBusinessDetail(scope.row.businessId)" - > - {{ scope.row.businessName }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="鍚堝悓閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="涓嬪崟鏃堕棿" - prop="orderDate" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓寮�濮嬫椂闂�" - prop="startTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓缁撴潫鏃堕棿" - prop="endTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column align="center" label="瀹㈡埛绛剧害浜�" prop="contactName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openContactDetail(scope.row.signContactId)" - > - {{ scope.row.signContactName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍏徃绛剧害浜�" prop="signUserName" width="130" /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - align="center" - label="宸插洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="鏈洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - > - <template #default="scope"> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.totalReceivablePrice) }} - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鍚堝悓鐘舵��" prop="auditStatus" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - <el-table-column fixed="right" label="鎿嶄綔" width="90"> - <template #default="scope"> - <el-button - link - v-hasPermi="['crm:contract:update']" - type="primary" - @click="handleProcessDetail(scope.row)" - > - 鏌ョ湅瀹℃壒 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts" name="EndContract"> -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import * as ContractApi from '@/api/crm/contract' -import { fenToYuanFormat } from '@/utils/formatter' -import { DICT_TYPE } from '@/utils/dict' -import { CONTRACT_EXPIRY_TYPE } from './common' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 鑷繁璐熻矗鐨� - expiryType: 1 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ContractApi.getContractPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鏌ョ湅瀹℃壒 */ -const handleProcessDetail = (row: ContractApi.ContractVO) => { - push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }) -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const openContactDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑鍟嗘満璇︽儏 */ -const openBusinessDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/backlog/components/CustomerFollowList.vue b/src/views/crm/backlog/components/CustomerFollowList.vue deleted file mode 100644 index 0f367a3..0000000 --- a/src/views/crm/backlog/components/CustomerFollowList.vue +++ /dev/null @@ -1,170 +0,0 @@ -<!-- 鍒嗛厤缁欐垜鐨勫鎴� --> -<!-- WHERE followUpStatus = ? --> -<template> - <ContentWrap> - <div class="pb-5 text-xl">鍒嗛厤缁欐垜鐨勫鎴�</div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鐘舵��" prop="followUpStatus"> - <el-select - v-model="queryParams.followUpStatus" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in FOLLOWUP_STATUS" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" fixed="left" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column align="center" label="閿佸畾鐘舵��" prop="lockStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎴愪氦鐘舵��" prop="dealStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column align="center" label="璺濈杩涘叆鍏捣澶╂暟" prop="poolDay" width="140"> - <template #default="scope"> {{ scope.row.poolDay }} 澶�</template> - </el-table-column> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import * as CustomerApi from '@/api/crm/customer' -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { FOLLOWUP_STATUS } from './common' - -defineOptions({ name: 'CrmCustomerFollowList' }) - -const { push } = useRouter() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - sceneType: 1, - followUpStatus: false -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getCustomerPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/backlog/components/CustomerPutPoolRemindList.vue b/src/views/crm/backlog/components/CustomerPutPoolRemindList.vue deleted file mode 100644 index 17f8df6..0000000 --- a/src/views/crm/backlog/components/CustomerPutPoolRemindList.vue +++ /dev/null @@ -1,169 +0,0 @@ -<!-- 寰呰繘鍏ュ叕娴风殑瀹㈡埛 --> -<template> - <ContentWrap> - <div class="pb-5 text-xl"> 寰呰繘鍏ュ叕娴风殑瀹㈡埛 </div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="褰掑睘" prop="sceneType"> - <el-select - v-model="queryParams.sceneType" - class="!w-240px" - placeholder="褰掑睘" - @change="handleQuery" - > - <el-option - v-for="(option, index) in SCENE_TYPES" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" fixed="left" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column align="center" label="閿佸畾鐘舵��" prop="lockStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎴愪氦鐘舵��" prop="dealStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column align="center" label="璺濈杩涘叆鍏捣澶╂暟" prop="poolDay" width="140"> - <template #default="scope"> {{ scope.row.poolDay }} 澶�</template> - </el-table-column> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { SCENE_TYPES } from './common' - -defineOptions({ name: 'CrmCustomerPutPoolRemindList' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - sceneType: 1, // 鎴戣礋璐g殑 - pool: true // 鍥哄畾 鍏捣鍙傛暟涓� true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getPutPoolRemindCustomerPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> - -<style lang="scss"></style> diff --git a/src/views/crm/backlog/components/CustomerTodayContactList.vue b/src/views/crm/backlog/components/CustomerTodayContactList.vue deleted file mode 100644 index 87aa31d..0000000 --- a/src/views/crm/backlog/components/CustomerTodayContactList.vue +++ /dev/null @@ -1,180 +0,0 @@ -<template> - <ContentWrap> - <div class="pb-5 text-xl"> 浠婃棩闇�鑱旂郴瀹㈡埛 </div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鐘舵��" prop="contactStatus"> - <el-select - v-model="queryParams.contactStatus" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in CONTACT_STATUS" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - <el-form-item label="褰掑睘" prop="sceneType"> - <el-select - v-model="queryParams.sceneType" - class="!w-240px" - placeholder="褰掑睘" - @change="handleQuery" - > - <el-option - v-for="(option, index) in SCENE_TYPES" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" fixed="left" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column align="center" label="閿佸畾鐘舵��" prop="lockStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎴愪氦鐘舵��" prop="dealStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column align="center" label="璺濈杩涘叆鍏捣澶╂暟" prop="poolDay" width="140"> - <template #default="scope"> {{ scope.row.poolDay }} 澶�</template> - </el-table-column> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { CONTACT_STATUS, SCENE_TYPES } from './common' - -defineOptions({ name: 'CrmCustomerTodayContactList' }) - -const { push } = useRouter() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - contactStatus: 1, - sceneType: 1, - pool: null // 鏄惁鍏捣鏁版嵁 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getCustomerPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> - -<style lang="scss"></style> diff --git a/src/views/crm/backlog/components/ReceivableAuditList.vue b/src/views/crm/backlog/components/ReceivableAuditList.vue deleted file mode 100644 index 2831d45..0000000 --- a/src/views/crm/backlog/components/ReceivableAuditList.vue +++ /dev/null @@ -1,201 +0,0 @@ -<!-- 寰呭鏍稿洖娆� --> -<template> - <ContentWrap> - <div class="pb-5 text-xl"> 寰呭鏍稿洖娆� </div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚堝悓鐘舵��" prop="auditStatus"> - <el-select - v-model="queryParams.auditStatus" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in AUDIT_STATUS" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column align="center" fixed="left" label="鍥炴缂栧彿" prop="no" width="180"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.no }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍚堝悓缂栧彿" prop="contractNo" width="180"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openContractDetail(scope.row.contractId)" - > - {{ scope.row.contract.no }} - </el-link> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="鍥炴鏃ユ湡" - prop="returnTime" - width="150px" - /> - <el-table-column - align="center" - label="鍥炴閲戦(鍏�)" - prop="price" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="鍥炴鏂瑰紡" prop="returnType" width="130px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="scope.row.returnType" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - align="center" - label="鍚堝悓閲戦锛堝厓锛�" - prop="contract.totalPrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鍥炴鐘舵��" prop="auditStatus" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="180px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:update']" - link - type="primary" - @click="handleProcessDetail(scope.row)" - > - 鏌ョ湅瀹℃壒 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import * as ReceivableApi from '@/api/crm/receivable' -import { AUDIT_STATUS } from './common' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CrmReceivableAuditList' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - auditStatus: 10 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ReceivableApi.getReceivablePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鏌ョ湅瀹℃壒 */ -const handleProcessDetail = (row: ReceivableApi.ReceivableVO) => { - push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }) -} - -/** 鎵撳紑鍥炴璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmReceivableDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const openContractDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/backlog/components/ReceivablePlanRemindList.vue b/src/views/crm/backlog/components/ReceivablePlanRemindList.vue deleted file mode 100644 index 9a3cf0c..0000000 --- a/src/views/crm/backlog/components/ReceivablePlanRemindList.vue +++ /dev/null @@ -1,220 +0,0 @@ -<!-- 寰呭洖娆炬彁閱� --> -<template> - <ContentWrap> - <div class="pb-5 text-xl">寰呭洖娆炬彁閱�</div> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍚堝悓鐘舵��" prop="remindType"> - <el-select - v-model="queryParams.remindType" - class="!w-240px" - placeholder="鐘舵��" - @change="handleQuery" - > - <el-option - v-for="(option, index) in RECEIVABLE_REMIND_TYPE" - :label="option.label" - :value="option.value" - :key="index" - /> - </el-select> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="150"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍚堝悓缂栧彿" prop="contractNo" width="200px" /> - <el-table-column align="center" label="鏈熸暟" prop="period"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.period }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="璁″垝鍥炴閲戦锛堝厓锛�" - prop="price" - width="160" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="璁″垝鍥炴鏃ユ湡" - prop="returnTime" - width="180px" - /> - <el-table-column align="center" label="鎻愬墠鍑犲ぉ鎻愰啋" prop="remindDays" width="150" /> - <el-table-column - align="center" - label="鎻愰啋鏃ユ湡" - prop="remindTime" - width="180px" - :formatter="dateFormatter2" - /> - <el-table-column align="center" label="鍥炴鏂瑰紡" prop="returnType" width="130px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="scope.row.returnType" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column - align="center" - label="瀹為檯鍥炴閲戦锛堝厓锛�" - prop="receivable.price" - width="160" - > - <template #default="scope"> - <el-text v-if="scope.row.receivable"> - {{ erpPriceInputFormatter(scope.row.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(0) }}</el-text> - </template> - </el-table-column> - <el-table-column - align="center" - label="瀹為檯鍥炴鏃ユ湡" - prop="receivable.returnTime" - width="180px" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="瀹為檯鍥炴閲戦锛堝厓锛�" - prop="receivable.price" - width="160" - > - <template #default="scope"> - <el-text v-if="scope.row.receivable"> - {{ erpPriceInputFormatter(scope.row.price - scope.row.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(scope.row.price) }}</el-text> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="180px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:create']" - link - type="success" - @click="openReceivableForm(scope.row)" - :disabled="scope.row.receivableId" - > - 鍒涘缓鍥炴 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ReceivableForm ref="receivableFormRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import { RECEIVABLE_REMIND_TYPE } from './common' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import ReceivableForm from '@/views/crm/receivable/ReceivableForm.vue' - -defineOptions({ name: 'ReceivablePlanRemindList' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - remindType: 1 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ReceivablePlanApi.getReceivablePlanPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鍒涘缓鍥炴鎿嶄綔 */ -const receivableFormRef = ref() -const openReceivableForm = (row: ReceivablePlanApi.ReceivablePlanVO) => { - receivableFormRef.value.open('create', undefined, row) -} - -/** 鎵撳紑璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmReceivablePlanDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - await getList() -}) - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> diff --git a/src/views/crm/backlog/components/common.ts b/src/views/crm/backlog/components/common.ts deleted file mode 100644 index 9ff6bfc..0000000 --- a/src/views/crm/backlog/components/common.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** 璺熻繘鐘舵�� */ -export const FOLLOWUP_STATUS = [ - { label: '寰呰窡杩�', value: false }, - { label: '宸茶窡杩�', value: true } -] - -/** 褰掑睘鑼冨洿 */ -export const SCENE_TYPES = [ - { label: '鎴戣礋璐g殑', value: 1 }, - { label: '鎴戝弬涓庣殑', value: 2 }, - { label: '涓嬪睘璐熻矗鐨�', value: 3 } -] - -/** 鑱旂郴鐘舵�� */ -export const CONTACT_STATUS = [ - { label: '浠婃棩闇�鑱旂郴', value: 1 }, - { label: '宸查�炬湡', value: 2 }, - { label: '宸茶仈绯�', value: 3 } -] - -/** 瀹℃壒鐘舵�� */ -export const AUDIT_STATUS = [ - { label: '寰呭鎵�', value: 10 }, - { label: '瀹℃牳閫氳繃', value: 20 }, - { label: '瀹℃牳涓嶉�氳繃', value: 30 } -] - -/** 鍥炴鎻愰啋绫诲瀷 */ -export const RECEIVABLE_REMIND_TYPE = [ - { label: '寰呭洖娆�', value: 1 }, - { label: '宸查�炬湡', value: 2 }, - { label: '宸插洖娆�', value: 3 } -] - -/** 鍚堝悓杩囨湡鐘舵�� */ -export const CONTRACT_EXPIRY_TYPE = [ - { label: '鍗冲皢杩囨湡', value: 1 }, - { label: '宸茶繃鏈�', value: 2 } -] diff --git a/src/views/crm/backlog/index.vue b/src/views/crm/backlog/index.vue deleted file mode 100644 index 49a1d4c..0000000 --- a/src/views/crm/backlog/index.vue +++ /dev/null @@ -1,177 +0,0 @@ -<template> - <doc-alert title="銆愰�氱敤銆戣窡杩涜褰曘�佸緟鍔炰簨椤�" url="https://doc.iocoder.cn/crm/follow-up/" /> - - <el-row :gutter="20"> - <el-col :span="4" class="min-w-[200px]"> - <div class="side-item-list"> - <div - v-for="(item, index) in leftSides" - :key="index" - :class="leftMenu == item.menu ? 'side-item-select' : 'side-item-default'" - class="side-item" - @click="sideClick(item)" - > - {{ item.name }} - <el-badge v-if="item.count > 0" :max="99" :value="item.count" /> - </div> - </div> - </el-col> - <el-col :span="20" :xs="24"> - <CustomerTodayContactList v-if="leftMenu === 'customerTodayContact'" /> - <ClueFollowList v-if="leftMenu === 'clueFollow'" /> - <ContractAuditList v-if="leftMenu === 'contractAudit'" /> - <ReceivableAuditList v-if="leftMenu === 'receivableAudit'" /> - <ContractRemindList v-if="leftMenu === 'contractRemind'" /> - <CustomerFollowList v-if="leftMenu === 'customerFollow'" /> - <CustomerPutPoolRemindList v-if="leftMenu === 'customerPutPoolRemind'" /> - <ReceivablePlanRemindList v-if="leftMenu === 'receivablePlanRemind'" /> - </el-col> - </el-row> -</template> - -<script lang="ts" setup> -import CustomerFollowList from './components/CustomerFollowList.vue' -import CustomerTodayContactList from './components/CustomerTodayContactList.vue' -import CustomerPutPoolRemindList from './components/CustomerPutPoolRemindList.vue' -import ClueFollowList from './components/ClueFollowList.vue' -import ContractAuditList from './components/ContractAuditList.vue' -import ContractRemindList from './components/ContractRemindList.vue' -import ReceivablePlanRemindList from './components/ReceivablePlanRemindList.vue' -import ReceivableAuditList from './components/ReceivableAuditList.vue' -import * as CustomerApi from '@/api/crm/customer' -import * as ClueApi from '@/api/crm/clue' -import * as ContractApi from '@/api/crm/contract' -import * as ReceivableApi from '@/api/crm/receivable' -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' - -defineOptions({ name: 'CrmBacklog' }) - -const leftMenu = ref('customerTodayContact') - -const clueFollowCount = ref(0) -const customerFollowCount = ref(0) -const customerPutPoolRemindCount = ref(0) -const customerTodayContactCount = ref(0) -const contractAuditCount = ref(0) -const contractRemindCount = ref(0) -const receivableAuditCount = ref(0) -const receivablePlanRemindCount = ref(0) - -const leftSides = ref([ - { - name: '浠婃棩闇�鑱旂郴瀹㈡埛', - menu: 'customerTodayContact', - count: customerTodayContactCount - }, - { - name: '鍒嗛厤缁欐垜鐨勭嚎绱�', - menu: 'clueFollow', - count: clueFollowCount - }, - { - name: '鍒嗛厤缁欐垜鐨勫鎴�', - menu: 'customerFollow', - count: customerFollowCount - }, - { - name: '寰呰繘鍏ュ叕娴风殑瀹㈡埛', - menu: 'customerPutPoolRemind', - count: customerPutPoolRemindCount - }, - { - name: '寰呭鏍稿悎鍚�', - menu: 'contractAudit', - count: contractAuditCount - }, - { - name: '寰呭鏍稿洖娆�', - menu: 'receivableAudit', - count: receivableAuditCount - }, - { - name: '寰呭洖娆炬彁閱�', - menu: 'receivablePlanRemind', - count: receivablePlanRemindCount - }, - { - name: '鍗冲皢鍒版湡鐨勫悎鍚�', - menu: 'contractRemind', - count: contractRemindCount - } -]) - -/** 渚ц竟鐐瑰嚮 */ -const sideClick = (item: any) => { - leftMenu.value = item.menu -} - -const getCount = () => { - CustomerApi.getTodayContactCustomerCount().then( - (count) => (customerTodayContactCount.value = count) - ) - CustomerApi.getPutPoolRemindCustomerCount().then( - (count) => (customerPutPoolRemindCount.value = count) - ) - CustomerApi.getFollowCustomerCount().then((count) => (customerFollowCount.value = count)) - ClueApi.getFollowClueCount().then((count) => (clueFollowCount.value = count)) - ContractApi.getAuditContractCount().then((count) => (contractAuditCount.value = count)) - ContractApi.getRemindContractCount().then((count) => (contractRemindCount.value = count)) - ReceivableApi.getAuditReceivableCount().then((count) => (receivableAuditCount.value = count)) - ReceivablePlanApi.getReceivablePlanRemindCount().then( - (count) => (receivablePlanRemindCount.value = count) - ) -} - -/** 婵�娲绘椂 */ -onActivated(async () => { - getCount() -}) - -/** 鍒濆鍖� */ -onMounted(async () => { - getCount() -}) -</script> - -<style lang="scss" scoped> -.side-item-list { - top: 0; - bottom: 0; - left: 0; - z-index: 1; - font-size: 14px; - background-color: var(--el-bg-color); - border: 1px solid var(--el-border-color); - border-radius: 5px; - - .side-item { - position: relative; - height: 50px; - padding: 0 20px; - line-height: 50px; - cursor: pointer; - } -} - -.side-item-default { - color: var(--el-text-color-primary); - border-right: 2px solid transparent; -} - -.side-item-select { - color: var(--el-color-primary); - background-color: var(--el-color-primary-light-9); - border-right: 2px solid var(--el-color-primary); -} - -.el-badge :deep(.el-badge__content) { - top: 0; - border: none; -} - -.el-badge { - position: absolute; - top: 0; - right: 15px; -} -</style> diff --git a/src/views/crm/business/BusinessForm.vue b/src/views/crm/business/BusinessForm.vue deleted file mode 100644 index 6b03047..0000000 --- a/src/views/crm/business/BusinessForm.vue +++ /dev/null @@ -1,287 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1280"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-row> - <el-col :span="8"> - <el-form-item label="鍟嗘満鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ晢鏈哄悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - :disabled="formData.customerDefault" - v-model="formData.customerId" - placeholder="璇烽�夋嫨瀹㈡埛" - class="w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="8"> - <el-form-item label="鍟嗘満鐘舵�佺粍" prop="statusTypeId"> - <el-select - v-model="formData.statusTypeId" - placeholder="璇烽�夋嫨鍟嗘満鐘舵�佺粍" - clearable - class="w-1/1" - :disabled="formType !== 'create'" - > - <el-option - v-for="item in statusTypeList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="棰勮鎴愪氦鏃ユ湡" prop="dealTime"> - <el-date-picker - v-model="formData.dealTime" - type="date" - value-format="x" - placeholder="閫夋嫨棰勮鎴愪氦鏃ユ湡" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="浜у搧娓呭崟" name="product"> - <BusinessProductForm - ref="productFormRef" - :products="formData.products" - :disabled="disabled" - /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row> - <el-col :span="8"> - <el-form-item label="浜у搧鎬婚噾棰�" prop="totalProductPrice"> - <el-input - disabled - v-model="formData.totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏁村崟鎶樻墸锛�%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - placeholder="璇疯緭鍏ユ暣鍗曟姌鎵�" - controls-position="right" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鎶樻墸鍚庨噾棰�" prop="price"> - <el-input - disabled - v-model="formData.totalPrice" - placeholder="璇疯緭鍏ュ晢鏈洪噾棰�" - :formatter="erpPriceTableColumnFormatter" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import * as BusinessStatusApi from '@/api/crm/business/status' -import * as CustomerApi from '@/api/crm/customer' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' -import BusinessProductForm from './components/BusinessProductForm.vue' -import { erpPriceMultiply, erpPriceTableColumnFormatter } from '@/utils' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - customerId: undefined, - ownerUserId: undefined, - statusTypeId: undefined, - dealTime: undefined, - discountPercent: 0, - totalProductPrice: undefined, - totalPrice: undefined, - remark: undefined, - products: [], - contactId: undefined, - customerDefault: false -}) -const formRules = reactive({ - name: [{ required: true, message: '鍟嗘満鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }], - statusTypeId: [{ required: true, message: '鍟嗘満鐘舵�佺粍涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const statusTypeList = ref([]) // 鍟嗘満鐘舵�佺被鍨嬪垪琛� -const customerList = ref([]) // 瀹㈡埛鍒楄〃鐨勬暟鎹� - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('product') -const productFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalProductPrice = val.products.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null - ? erpPriceMultiply(totalProductPrice, val.discountPercent / 100.0) - : 0 - const totalPrice = totalProductPrice - discountPrice - // 璧嬪�� - formData.value.totalProductPrice = totalProductPrice - formData.value.totalPrice = totalPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number, customerId?: number, contactId?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await BusinessApi.getBusiness(id) - } finally { - formLoading.value = false - } - } else { - if (customerId) { - formData.value.customerId = customerId - formData.value.customerDefault = true // 榛樿瀹㈡埛鐨勯�夋嫨锛屼笉鍏佽鍙� - } - // 鑷姩鍏宠仈 contactId 鑱旂郴浜虹紪鍙� - if (contactId) { - formData.value.contactId = contactId - } - } - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鍔犺浇鍟嗘満鐘舵�佺被鍨嬪垪琛� - statusTypeList.value = await BusinessStatusApi.getBusinessStatusTypeSimpleList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - await productFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as BusinessApi.BusinessVO - if (formType.value === 'create') { - await BusinessApi.createBusiness(data) - message.success(t('common.createSuccess')) - } else { - await BusinessApi.updateBusiness(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - customerId: undefined, - ownerUserId: undefined, - statusTypeId: undefined, - dealTime: undefined, - discountPercent: 0, - totalProductPrice: undefined, - totalPrice: undefined, - remark: undefined, - products: [], - contactId: undefined, - customerDefault: false - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/business/BusinessUpdateStatusForm.vue b/src/views/crm/business/BusinessUpdateStatusForm.vue deleted file mode 100644 index 4f2f761..0000000 --- a/src/views/crm/business/BusinessUpdateStatusForm.vue +++ /dev/null @@ -1,108 +0,0 @@ -<template> - <Dialog title="鍙樻洿鍟嗘満鐘舵��" v-model="dialogVisible" width="400"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="80px" - v-loading="formLoading" - > - <el-form-item label="鍟嗘満闃舵" prop="status"> - <el-select v-model="formData.status" placeholder="璇烽�夋嫨鍟嗘満闃舵" class="w-1/1"> - <el-option - v-for="item in statusList" - :key="item.id" - :label="item.name + '(璧㈠崟鐜囷細' + item.percent + '%)'" - :value="item.id" - /> - <el-option - v-for="item in BusinessStatusApi.DEFAULT_STATUSES" - :key="item.endStatus" - :label="item.name + '(璧㈠崟鐜囷細' + item.percent + '%)'" - :value="-item.endStatus" - /> - </el-select> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import * as BusinessStatusApi from '@/api/crm/business/status' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - id: undefined, - statusId: undefined, - endStatus: undefined, - status: undefined -}) -const formRules = reactive({ - status: [{ required: true, message: '鍟嗘満闃舵涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const statusList = ref([]) // 鍟嗘満鐘舵�佸垪琛� - -/** 鎵撳紑寮圭獥 */ -const open = async (business: BusinessApi.BusinessVO) => { - dialogVisible.value = true - resetForm() - formData.value = { - id: business.id, - statusId: business.statusId, - endStatus: business.endStatus, - status: business.endStatus != null ? -business.endStatus : business.statusId - } - // 鍔犺浇鐘舵�佸垪琛� - formLoading.value = true - try { - statusList.value = await BusinessStatusApi.getBusinessStatusSimpleList(business.statusTypeId) - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await BusinessApi.updateBusinessStatus({ - id: formData.value.id, - statusId: formData.value.status > 0 ? formData.value.status : undefined, - endStatus: formData.value.status < 0 ? -formData.value.status : undefined - }) - message.success('鏇存柊鍟嗘満鐘舵�佹垚鍔�') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - statusId: undefined, - endStatus: undefined, - status: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/business/components/BusinessList.vue b/src/views/crm/business/components/BusinessList.vue deleted file mode 100644 index f990606..0000000 --- a/src/views/crm/business/components/BusinessList.vue +++ /dev/null @@ -1,186 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row justify="end"> - <el-button @click="openForm"> - <Icon class="mr-5px" icon="ep:opportunity" /> - 鍒涘缓鍟嗘満 - </el-button> - <el-button - @click="openBusinessModal" - v-hasPermi="['crm:contact:create-business']" - v-if="queryParams.contactId" - > - <Icon class="mr-5px" icon="ep:circle-plus" />鍏宠仈 - </el-button> - <el-button - @click="deleteContactBusinessList" - v-hasPermi="['crm:contact:delete-business']" - v-if="queryParams.contactId" - > - <Icon class="mr-5px" icon="ep:remove" />瑙i櫎鍏宠仈 - </el-button> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table - ref="businessRef" - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - > - <el-table-column type="selection" width="55" v-if="queryParams.contactId" /> - <el-table-column label="鍟嗘満鍚嶇О" fixed="left" align="center" prop="name"> - <template #default="scope"> - <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column - label="鍟嗘満閲戦" - align="center" - prop="price" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="瀹㈡埛鍚嶇О" align="center" prop="customerName" /> - <el-table-column label="鍟嗘満缁�" align="center" prop="statusTypeName" /> - <el-table-column label="鍟嗘満闃舵" align="center" prop="statusName" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <BusinessForm ref="formRef" @success="getList" /> - <!-- 鍏宠仈鍟嗘満閫夋嫨寮规 --> - <BusinessListModal - ref="businessModalRef" - :customer-id="props.customerId" - @success="createContactBusinessList" - /> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import * as ContactApi from '@/api/crm/contact' -import BusinessForm from './../BusinessForm.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import BusinessListModal from './BusinessListModal.vue' -import { erpPriceTableColumnFormatter } from '@/utils' - -const message = useMessage() // 娑堟伅 - -defineOptions({ name: 'CrmBusinessList' }) -const props = defineProps<{ - bizType: number // 涓氬姟绫诲瀷 - bizId: number // 涓氬姟缂栧彿 - customerId?: number // 鍏宠仈鑱旂郴浜轰笌鍟嗘満鏃讹紝闇�瑕佷紶鍏� customerId 杩涜绛涢�� - contactId?: number // 鐗规畩锛氳仈绯讳汉缂栧彿锛涘湪銆愯仈绯讳汉銆戣鎯呬腑锛屽彲浠ヤ紶閫掕仈绯讳汉缂栧彿锛岄粯璁ゆ柊寤虹殑鍟嗘満鍏宠仈鍒拌鑱旂郴浜� -}>() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - customerId: undefined as unknown, // 鍏佽 undefined + number - contactId: undefined as unknown // 鍏佽 undefined + number -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 缃┖鍙傛暟 - queryParams.customerId = undefined - queryParams.contactId = undefined - // 鎵ц鏌ヨ - let data = { list: [], total: 0 } - switch (props.bizType) { - case BizTypeEnum.CRM_CUSTOMER: - queryParams.customerId = props.bizId - data = await BusinessApi.getBusinessPageByCustomer(queryParams) - break - case BizTypeEnum.CRM_CONTACT: - queryParams.contactId = props.bizId - data = await BusinessApi.getBusinessPageByContact(queryParams) - break - default: - return - } - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 娣诲姞鎿嶄綔 */ -const formRef = ref() -const openForm = () => { - formRef.value.open('create', null, props.customerId, props.contactId) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 鎵撳紑鑱旂郴浜轰笌鍟嗘満鐨勫叧鑱斿脊绐� */ -const businessModalRef = ref() -const openBusinessModal = () => { - businessModalRef.value.open() -} -const createContactBusinessList = async (businessIds: number[]) => { - const data = { - contactId: props.bizId, - businessIds: businessIds - } as ContactApi.ContactBusinessReqVO - businessRef.value.getSelectionRows().forEach((row: BusinessApi.BusinessVO) => { - data.businessIds.push(row.id) - }) - await ContactApi.createContactBusinessList(data) - // 鍒锋柊鍒楄〃 - message.success('鍏宠仈鍟嗘満鎴愬姛') - handleQuery() -} - -/** 瑙i櫎鑱旂郴浜轰笌鍟嗘満鐨勫叧鑱� */ -const businessRef = ref() -const deleteContactBusinessList = async () => { - const data = { - contactId: props.bizId, - businessIds: businessRef.value.getSelectionRows().map((row: BusinessApi.BusinessVO) => row.id) - } as ContactApi.ContactBusinessReqVO - if (data.businessIds.length === 0) { - return message.error('鏈�夋嫨鍟嗘満') - } - await ContactApi.deleteContactBusinessList(data) - // 鍒锋柊鍒楄〃 - message.success('鍙栧叧鍟嗘満鎴愬姛') - handleQuery() -} - -/** 鐩戝惉鎵撳紑鐨� bizId + bizType锛屼粠鑰屽姞杞芥渶鏂扮殑鍒楄〃 */ -watch( - () => [props.bizId, props.bizType], - () => { - handleQuery() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/business/components/BusinessListModal.vue b/src/views/crm/business/components/BusinessListModal.vue deleted file mode 100644 index 3c21f06..0000000 --- a/src/views/crm/business/components/BusinessListModal.vue +++ /dev/null @@ -1,156 +0,0 @@ -<template> - <Dialog title="鍏宠仈鍟嗘満" v-model="dialogVisible"> - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍟嗘満鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ晢鏈哄悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" @click="openForm()" v-hasPermi="['crm:business:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table - v-loading="loading" - ref="businessRef" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - > - <el-table-column type="selection" width="55" /> - <el-table-column label="鍟嗘満鍚嶇О" fixed="left" align="center" prop="name"> - <template #default="scope"> - <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column - label="鍟嗘満閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="瀹㈡埛鍚嶇О" align="center" prop="customerName" /> - <el-table-column label="鍟嗘満缁�" align="center" prop="statusTypeName" /> - <el-table-column label="鍟嗘満闃舵" align="center" prop="statusName" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <BusinessForm ref="formRef" @success="getList" /> - </Dialog> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import BusinessForm from '../BusinessForm.vue' -import { erpPriceTableColumnFormatter } from '@/utils' - -const message = useMessage() // 娑堟伅寮圭獥 -const props = defineProps<{ - customerId: number -}>() -defineOptions({ name: 'BusinessListModal' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - customerId: props.customerId -}) - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - queryParams.customerId = props.customerId // 瑙e喅 props.customerId 娌℃洿鏂板埌 queryParams 涓婄殑闂 - await getList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BusinessApi.getBusinessPageByCustomer(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞鎿嶄綔 */ -const formRef = ref() -const openForm = () => { - formRef.value.open('create') -} - -/** 鍏宠仈鍟嗘満鎻愪氦 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const businessRef = ref() -const submitForm = async () => { - const businessIds = businessRef.value - .getSelectionRows() - .map((row: BusinessApi.BusinessVO) => row.id) - if (businessIds.length === 0) { - return message.error('鏈�夋嫨鍟嗘満') - } - dialogVisible.value = false - emit('success', businessIds, businessRef.value.getSelectionRows()) -} - -/** 鎵撳紑鍟嗘満璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} -</script> diff --git a/src/views/crm/business/components/BusinessProductForm.vue b/src/views/crm/business/components/BusinessProductForm.vue deleted file mode 100644 index fbba065..0000000 --- a/src/views/crm/business/components/BusinessProductForm.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productNo" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" /> - </template> - </el-table-column> - <el-table-column label="浠锋牸锛堝厓锛�" min-width="120"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍞环锛堝厓锛�" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.businessPrice`" class="mb-0px!"> - <el-input-number - v-model="row.businessPrice" - controls-position="right" - :min="0.001" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣" prop="totalPrice" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import * as ProductApi from '@/api/crm/product' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import { DICT_TYPE } from '@/utils/dict' - -const props = defineProps<{ - products: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - businessPrice: [{ required: true, message: '鍚堝悓浠锋牸涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductApi.ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃骇鍝侀」 */ -watch( - () => props.products, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - if (item.businessPrice != null && item.count != null) { - item.totalPrice = erpPriceMultiply(item.businessPrice, item.count) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnit: undefined, // 浜у搧鍗曚綅 - productNo: undefined, // 浜у搧鏉$爜 - productPrice: undefined, // 浜у搧浠锋牸 - businessPrice: undefined, - count: 1 - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnit = product.unit - row.productNo = product.no - row.productPrice = product.price - row.businessPrice = product.price - } -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() -}) -</script> diff --git a/src/views/crm/business/detail/BusinessDetailsHeader.vue b/src/views/crm/business/detail/BusinessDetailsHeader.vue deleted file mode 100644 index 50d1efe..0000000 --- a/src/views/crm/business/detail/BusinessDetailsHeader.vue +++ /dev/null @@ -1,37 +0,0 @@ -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ business.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ business.customerName }}</el-descriptions-item> - <el-descriptions-item label="鍟嗘満閲戦锛堝厓锛�"> - {{ erpPriceInputFormatter(business.totalPrice) }} - </el-descriptions-item> - <el-descriptions-item label="鍟嗘満缁�">{{ business.statusTypeName }}</el-descriptions-item> - <el-descriptions-item label="璐熻矗浜�">{{ business.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(business.createTime) }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as BusinessApi from '@/api/crm/business' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { business } = defineProps<{ business: BusinessApi.BusinessVO }>() -</script> diff --git a/src/views/crm/business/detail/BusinessDetailsInfo.vue b/src/views/crm/business/detail/BusinessDetailsInfo.vue deleted file mode 100644 index a2c9ce1..0000000 --- a/src/views/crm/business/detail/BusinessDetailsInfo.vue +++ /dev/null @@ -1,61 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="鍟嗘満濮撳悕">{{ business.name }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ business.customerName }}</el-descriptions-item> - <el-descriptions-item label="鍟嗘満閲戦锛堝厓锛�"> - {{ erpPriceInputFormatter(business.totalPrice) }} - </el-descriptions-item> - <el-descriptions-item label="棰勮鎴愪氦鏃ユ湡"> - {{ formatDate(business.dealTime) }} - </el-descriptions-item> - <el-descriptions-item label="涓嬫鑱旂郴鏃堕棿"> - {{ formatDate(business.contactNextTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍟嗘満鐘舵�佺粍"> - {{ business.statusTypeName }} - </el-descriptions-item> - <el-descriptions-item label="鍟嗘満闃舵">{{ business.statusName }}</el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ business.remark }}</el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�">{{ business.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涙椂闂�"> - {{ formatDate(business.contactLastTime) }} - </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�">{{ business.creatorName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(business.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(business.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { business } = defineProps<{ - business: BusinessApi.BusinessVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['basicInfo', 'systemInfo']) -</script> diff --git a/src/views/crm/business/detail/BusinessProductList.vue b/src/views/crm/business/detail/BusinessProductList.vue deleted file mode 100644 index 9a31665..0000000 --- a/src/views/crm/business/detail/BusinessProductList.vue +++ /dev/null @@ -1,66 +0,0 @@ -<template> - <ContentWrap> - <el-table :data="business.products" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column - align="center" - label="浜у搧鍚嶇О" - fixed="left" - prop="productName" - min-width="160" - > - <template #default="scope"> - {{ scope.row.productName }} - </template> - </el-table-column> - <el-table-column label="浜у搧鏉$爜" align="center" prop="productNo" min-width="120" /> - <el-table-column align="center" label="浜у搧鍗曚綅" prop="productUnit" min-width="160"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" /> - </template> - </el-table-column> - <el-table-column - label="浜у搧浠锋牸锛堝厓锛�" - align="center" - prop="productPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍟嗘満浠锋牸锛堝厓锛�" - align="center" - prop="businessPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="鏁伴噺" - prop="count" - min-width="100px" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚堣閲戦锛堝厓锛�" - align="center" - prop="totalPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <el-row class="mt-10px" justify="end"> - <el-col :span="3"> 鏁村崟鎶樻墸锛歿{ erpPriceInputFormatter(business.discountPercent) }}% </el-col> - <el-col :span="4"> - 浜у搧鎬婚噾棰濓細{{ erpPriceInputFormatter(business.totalProductPrice) }} 鍏� - </el-col> - </el-row> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as BusinessApi from '@/api/crm/business' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { DICT_TYPE } from '@/utils/dict' - -const { business } = defineProps<{ - business: BusinessApi.BusinessVO -}>() -</script> diff --git a/src/views/crm/business/detail/index.vue b/src/views/crm/business/detail/index.vue deleted file mode 100644 index dbab819..0000000 --- a/src/views/crm/business/detail/index.vue +++ /dev/null @@ -1,146 +0,0 @@ -<template> - <BusinessDetailsHeader v-loading="loading" :business="business"> - <el-button v-if="permissionListRef?.validateWrite" @click="openForm('update', business.id)"> - 缂栬緫 - </el-button> - <el-button - v-if="permissionListRef?.validateWrite" - :disabled="business.endStatus" - type="success" - @click="openStatusForm()" - > - 鍙樻洿鍟嗘満鐘舵�� - </el-button> - <el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transfer"> - 杞Щ - </el-button> - </BusinessDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璺熻繘璁板綍"> - <FollowUpList :biz-id="businessId" :biz-type="BizTypeEnum.CRM_BUSINESS" /> - </el-tab-pane> - <el-tab-pane label="璇︾粏璧勬枡"> - <BusinessDetailsInfo :business="business" /> - </el-tab-pane> - <el-tab-pane label="鑱旂郴浜�" lazy> - <ContactList - :biz-id="business.id!" - :biz-type="BizTypeEnum.CRM_BUSINESS" - :business-id="business.id" - :customer-id="business.customerId" - /> - </el-tab-pane> - <el-tab-pane label="浜у搧"> - <BusinessProductList :business="business" /> - </el-tab-pane> - <el-tab-pane label="鍚堝悓" lazy> - <ContractList :biz-id="business.id!" :biz-type="BizTypeEnum.CRM_BUSINESS" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="business.id!" - :biz-type="BizTypeEnum.CRM_BUSINESS" - :show-action="true" - @quit-team="close" - /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BusinessForm ref="formRef" @success="getBusiness" /> - <BusinessUpdateStatusForm ref="statusFormRef" @success="getBusiness" /> - <CrmTransferForm ref="transferFormRef" :biz-type="BizTypeEnum.CRM_BUSINESS" @success="close" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as BusinessApi from '@/api/crm/business' -import BusinessDetailsHeader from './BusinessDetailsHeader.vue' -import BusinessDetailsInfo from './BusinessDetailsInfo.vue' -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import { BizTypeEnum } from '@/api/crm/permission' -import { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' -import BusinessForm from '@/views/crm/business/BusinessForm.vue' -import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue' -import FollowUpList from '@/views/crm/followup/index.vue' -import ContactList from '@/views/crm/contact/components/ContactList.vue' -import BusinessUpdateStatusForm from '@/views/crm/business/BusinessUpdateStatusForm.vue' -import ContractList from '@/views/crm/contract/components/ContractList.vue' -import BusinessProductList from '@/views/crm/business/detail/BusinessProductList.vue' - -defineOptions({ name: 'CrmBusinessDetail' }) - -const message = useMessage() - -const businessId = ref(0) // 绾跨储缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const business = ref<BusinessApi.BusinessVO>({} as BusinessApi.BusinessVO) // 鍟嗘満璇︽儏 -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const getBusiness = async () => { - loading.value = true - try { - business.value = await BusinessApi.getBusiness(businessId.value) - await getOperateLog(businessId.value) - } finally { - loading.value = false - } -} - -/** 缂栬緫 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍙樻洿鍟嗘満鐘舵�� */ -const statusFormRef = ref() -const openStatusForm = () => { - statusFormRef.value.open(business.value) -} - -/** 鑱旂郴浜鸿浆绉� */ -const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // 鑱旂郴浜鸿浆绉昏〃鍗� ref -const transfer = () => { - transferFormRef.value?.open(business.value.id) -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (contactId: number) => { - if (!contactId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_BUSINESS, - bizId: contactId - }) - logList.value = data.list -} - -/** 鍏抽棴绐楀彛 */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(async () => { - if (!params.id) { - message.warning('鍙傛暟閿欒锛屽晢鏈轰笉鑳戒负绌猴紒') - close() - return - } - businessId.value = params.id as unknown as number - await getBusiness() -}) -</script> diff --git a/src/views/crm/business/index.vue b/src/views/crm/business/index.vue deleted file mode 100644 index 84e447c..0000000 --- a/src/views/crm/business/index.vue +++ /dev/null @@ -1,275 +0,0 @@ -<template> - <doc-alert title="銆愬晢鏈恒�戝晢鏈虹鐞嗐�佸晢鏈虹姸鎬�" url="https://doc.iocoder.cn/crm/business/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍟嗘満鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ晢鏈哄悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['crm:business:create']" type="primary" @click="openForm('create')"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['crm:business:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鍟嗘満鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column - :formatter="erpPriceTableColumnFormatter" - align="center" - label="鍟嗘満閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="棰勮鎴愪氦鏃ユ湡" - prop="dealTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満鐘舵�佺粍" - prop="statusTypeName" - width="140" - /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満闃舵" - prop="statusName" - width="120" - /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="130px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:business:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:business:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BusinessForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as BusinessApi from '@/api/crm/business' -import BusinessForm from './BusinessForm.vue' -import { erpPriceTableColumnFormatter } from '@/utils' -import { TabsPaneContext } from 'element-plus' - -defineOptions({ name: 'CrmBusiness' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - name: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BusinessApi.getBusinessPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await BusinessApi.deleteBusiness(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await BusinessApi.exportBusiness(queryParams) - download.excel(data, '鍟嗘満.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/business/status/BusinessStatusForm.vue b/src/views/crm/business/status/BusinessStatusForm.vue deleted file mode 100644 index d6a4d6f..0000000 --- a/src/views/crm/business/status/BusinessStatusForm.vue +++ /dev/null @@ -1,194 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鐘舵�佺粍鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ姸鎬佺粍鍚�" /> - </el-form-item> - <el-form-item label="搴旂敤閮ㄩ棬" prop="deptIds"> - <template #label> - <Tooltip message="涓嶉�夋嫨閮ㄩ棬鏃讹紝榛樿鍏ㄥ叕鍙哥敓鏁�" title="搴旂敤閮ㄩ棬" /> - </template> - <el-tree - ref="treeRef" - :data="deptList" - :props="defaultProps" - :check-strictly="!checkStrictly" - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - show-checkbox - /> - </el-form-item> - <el-form-item label="闃舵璁剧疆" prop="statuses"> - <el-table - border - style="width: 100%" - :data="formData.statuses.concat(BusinessStatusApi.DEFAULT_STATUSES)" - > - <el-table-column align="center" label="闃舵" width="70"> - <template #default="scope"> - <el-text v-if="!scope.row.defaultStatus">闃舵 {{ scope.$index + 1 }}</el-text> - <el-text v-else>缁撴潫</el-text> - </template> - </el-table-column> - <el-table-column align="center" label="闃舵鍚嶇О" width="160" prop="name"> - <template #default="{ row }"> - <el-input v-if="!row.endStatus" v-model="row.name" placeholder="璇疯緭鍏ョ姸鎬佸悕绉�" /> - <el-text v-else>{{ row.name }}</el-text> - </template> - </el-table-column> - <el-table-column width="140" align="center" label="璧㈠崟鐜囷紙%锛�" prop="percent"> - <template #default="{ row }"> - <el-input-number - v-if="!row.endStatus" - v-model="row.percent" - placeholder="璇疯緭鍏ヨ耽鍗曠巼" - controls-position="right" - :min="0" - :max="100" - :precision="2" - class="!w-1/1" - /> - <el-text v-else>{{ row.percent }}</el-text> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" width="110" align="center"> - <template #default="scope"> - <el-button - v-if="!scope.row.endStatus" - link - type="primary" - @click="addStatus(scope.$index)" - > - 娣诲姞 - </el-button> - <el-button - v-if="!scope.row.endStatus" - link - type="danger" - @click="deleteStatusArea(scope.$index)" - :disabled="formData.statuses.length <= 1" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as BusinessStatusApi from '@/api/crm/business/status' -import { defaultProps, handleTree } from '@/utils/tree' -import * as DeptApi from '@/api/system/dept' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭粍锛歝reate - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '', - deptIds: [], - statuses: [] -}) -const formRules = reactive({ - name: [{ required: true, message: '鐘舵�佺粍鍚嶄笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const deptList = ref<Tree[]>([]) // 鏍戝舰缁撴瀯 -const treeRef = ref() // 鑿滃崟鏍戠粍浠� Ref -const checkStrictly = ref(true) // 鏄惁涓ユ牸妯″紡锛屽嵆鐖跺瓙涓嶅叧鑱� - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await BusinessStatusApi.getBusinessStatus(id) - treeRef.value.setCheckedKeys(formData.value.deptIds) - if (formData.value.statuses.length == 0) { - addStatus() - } - } finally { - formLoading.value = false - } - } else { - addStatus() - } - // 鍔犺浇閮ㄩ棬鏍� - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as BusinessStatusApi.BusinessStatusTypeVO - data.deptIds = treeRef.value.getCheckedKeys(false) - if (formType.value === 'create') { - await BusinessStatusApi.createBusinessStatus(data) - message.success(t('common.createSuccess')) - } else { - await BusinessStatusApi.updateBusinessStatus(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - checkStrictly.value = true - formData.value = { - id: undefined, - name: '', - deptIds: [], - statuses: [] - } - treeRef.value?.setCheckedNodes([]) - formRef.value?.resetFields() -} - -/** 娣诲姞鐘舵�� */ -const addStatus = () => { - const data = formData.value - data.statuses.push({ - name: '', - percent: undefined - }) -} - -/** 鍒犻櫎鐘舵�� */ -const deleteStatusArea = (index: number) => { - const data = formData.value - data.statuses.splice(index, 1) -} -</script> diff --git a/src/views/crm/business/status/index.vue b/src/views/crm/business/status/index.vue deleted file mode 100644 index ef51488..0000000 --- a/src/views/crm/business/status/index.vue +++ /dev/null @@ -1,150 +0,0 @@ -<template> - <doc-alert title="銆愬晢鏈恒�戝晢鏈虹鐞嗐�佸晢鏈虹姸鎬�" url="https://doc.iocoder.cn/crm/business/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['crm:business-status:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鐘舵�佺粍鍚�" align="center" prop="name" /> - <el-table-column label="搴旂敤閮ㄩ棬" align="center" prop="deptNames"> - <template #default="scope"> - <span v-if="scope.row?.deptNames?.length > 0"> - {{ scope.row.deptNames.join(' ') }} - </span> - <span v-else>鍏ㄥ叕鍙�</span> - </template> - </el-table-column> - <el-table-column label="鍒涘缓浜�" align="center" prop="creator" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['crm:business-status:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['crm:business-status:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BusinessStatusForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as BusinessStatusApi from '@/api/crm/business/status' -import BusinessStatusForm from './BusinessStatusForm.vue' -import { deleteBusinessStatus } from '@/api/crm/business/status' - -defineOptions({ name: 'CrmBusinessStatus' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BusinessStatusApi.getBusinessStatusPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await BusinessStatusApi.deleteBusinessStatus(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/clue/ClueForm.vue b/src/views/crm/clue/ClueForm.vue deleted file mode 100644 index 82a1320..0000000 --- a/src/views/crm/clue/ClueForm.vue +++ /dev/null @@ -1,259 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="绾跨储鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ嚎绱㈠悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鏉ユ簮" prop="source"> - <el-select v-model="formData.source" placeholder="璇烽�夋嫨瀹㈡埛鏉ユ簮" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鎵嬫満" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鐢佃瘽" prop="telephone"> - <el-input v-model="formData.telephone" placeholder="璇疯緭鍏ョ數璇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閭" prop="email"> - <el-input v-model="formData.email" placeholder="璇疯緭鍏ラ偖绠�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="寰俊" prop="wechat"> - <el-input v-model="formData.wechat" placeholder="璇疯緭鍏ュ井淇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="QQ" prop="qq"> - <el-input v-model="formData.qq" placeholder="璇疯緭鍏� QQ" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛琛屼笟" prop="industryId"> - <el-select v-model="formData.industryId" placeholder="璇烽�夋嫨瀹㈡埛琛屼笟" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="瀹㈡埛绾у埆" prop="level"> - <el-select v-model="formData.level" placeholder="璇烽�夋嫨瀹㈡埛绾у埆" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍦板潃" prop="areaId"> - <el-cascader - v-model="formData.areaId" - :options="areaList" - :props="defaultProps" - class="w-1/1" - clearable - filterable - placeholder="璇烽�夋嫨鍩庡競" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璇︾粏鍦板潃" prop="detailAddress"> - <el-input v-model="formData.detailAddress" placeholder="璇疯緭鍏ヨ缁嗗湴鍧�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="涓嬫鑱旂郴鏃堕棿" prop="contactNextTime"> - <el-date-picker - v-model="formData.contactNextTime" - placeholder="閫夋嫨涓嬫鑱旂郴鏃堕棿" - type="datetime" - value-format="x" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as ClueApi from '@/api/crm/clue' -import * as AreaApi from '@/api/system/area' -import { defaultProps } from '@/utils/tree' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const areaList = ref([]) // 鍦板尯鍒楄〃 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const formData = ref({ - id: undefined, - name: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - industryId: undefined, - level: undefined, - source: undefined, - remark: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '绾跨储鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ClueApi.getClue(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱鍦板尯鍒楄〃 - areaList.value = await AreaApi.getAreaTree() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ClueApi.ClueVO - if (formType.value === 'create') { - await ClueApi.createClue(data) - message.success(t('common.createSuccess')) - } else { - await ClueApi.updateClue(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - industryId: undefined, - level: undefined, - source: undefined, - remark: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/clue/detail/ClueDetailsHeader.vue b/src/views/crm/clue/detail/ClueDetailsHeader.vue deleted file mode 100644 index 41552c7..0000000 --- a/src/views/crm/clue/detail/ClueDetailsHeader.vue +++ /dev/null @@ -1,43 +0,0 @@ -<template> - <div v-loading="loading"> - <div class="flex items-start justify-between"> - <div> - <!-- 宸︿笂锛氱嚎绱㈠熀鏈俊鎭� --> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ clue.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="绾跨储鏉ユ簮"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="clue.source" /> - </el-descriptions-item> - <el-descriptions-item label="鎵嬫満"> {{ clue.mobile }} </el-descriptions-item> - <el-descriptions-item label="璐熻矗浜�"> - {{ clue.ownerUserName }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(clue.createTime) }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import * as ClueApi from '@/api/crm/clue' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'CrmClueDetailsHeader' }) -defineProps<{ - clue: ClueApi.ClueVO // 绾跨储淇℃伅 - loading: boolean // 鍔犺浇涓� -}>() -</script> diff --git a/src/views/crm/clue/detail/ClueDetailsInfo.vue b/src/views/crm/clue/detail/ClueDetailsInfo.vue deleted file mode 100644 index 5a1d01f..0000000 --- a/src/views/crm/clue/detail/ClueDetailsInfo.vue +++ /dev/null @@ -1,72 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames" class=""> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="绾跨储鍚嶇О"> - {{ clue.name }} - </el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鏉ユ簮"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="clue.source" /> - </el-descriptions-item> - <el-descriptions-item label="鎵嬫満">{{ clue.mobile }}</el-descriptions-item> - <el-descriptions-item label="鐢佃瘽">{{ clue.telephone }}</el-descriptions-item> - <el-descriptions-item label="閭">{{ clue.email }}</el-descriptions-item> - <el-descriptions-item label="鍦板潃"> - {{ clue.areaName }} {{ clue.detailAddress }} - </el-descriptions-item> - <el-descriptions-item label="QQ">{{ clue.qq }}</el-descriptions-item> - <el-descriptions-item label="寰俊">{{ clue.wechat }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛琛屼笟"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="clue.industryId" /> - </el-descriptions-item> - <el-descriptions-item label="瀹㈡埛绾у埆"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="clue.level" /> - </el-descriptions-item> - <el-descriptions-item label="涓嬫鑱旂郴鏃堕棿"> - {{ formatDate(clue.contactNextTime) }} - </el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ clue.remark }}</el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�">{{ clue.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涜褰�"> - {{ clue.contactLastContent }} - </el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涙椂闂�"> - {{ formatDate(clue.contactLastTime) }} - </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�">{{ clue.creatorName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(clue.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(clue.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ClueApi from '@/api/crm/clue' -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'CrmClueDetailsInfo' }) -const { clue } = defineProps<{ - clue: ClueApi.ClueVO // 绾跨储鏄庣粏 -}>() - -const activeNames = ref(['basicInfo', 'systemInfo']) // 灞曠ず鐨勬姌鍙犻潰鏉� -</script> -<style lang="scss" scoped></style> diff --git a/src/views/crm/clue/detail/index.vue b/src/views/crm/clue/detail/index.vue deleted file mode 100644 index 4c211e6..0000000 --- a/src/views/crm/clue/detail/index.vue +++ /dev/null @@ -1,130 +0,0 @@ -<template> - <ClueDetailsHeader :clue="clue" :loading="loading"> - <el-button - v-if="permissionListRef?.validateWrite" - v-hasPermi="['crm:clue:update']" - type="primary" - @click="openForm" - > - 缂栬緫 - </el-button> - <el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transfer"> - 杞Щ - </el-button> - <el-button - v-if="permissionListRef?.validateOwnerUser && !clue.transformStatus" - type="success" - @click="handleTransform" - > - 杞寲涓哄鎴� - </el-button> - <el-button v-else disabled type="success">宸茶浆鍖栧鎴�</el-button> - </ClueDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璺熻繘璁板綍"> - <FollowUpList :biz-id="clueId" :biz-type="BizTypeEnum.CRM_CLUE" /> - </el-tab-pane> - <el-tab-pane label="鍩烘湰淇℃伅"> - <ClueDetailsInfo :clue="clue" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="clue.id!" - :biz-type="BizTypeEnum.CRM_CLUE" - :show-action="true" - @quit-team="close" - /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ClueForm ref="formRef" @success="getClue" /> - <CrmTransferForm ref="transferFormRef" :biz-type="BizTypeEnum.CRM_CLUE" @success="close" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as ClueApi from '@/api/crm/clue' -import ClueForm from '@/views/crm/clue/ClueForm.vue' -import ClueDetailsHeader from './ClueDetailsHeader.vue' // 绾跨储鏄庣粏 - 澶撮儴 -import ClueDetailsInfo from './ClueDetailsInfo.vue' // 绾跨储鏄庣粏 - 璇︾粏淇℃伅 -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue' -import FollowUpList from '@/views/crm/followup/index.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import type { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' - -defineOptions({ name: 'CrmClueDetail' }) - -const clueId = ref(0) // 绾跨储缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const message = useMessage() // 娑堟伅寮圭獥 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 - -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const clue = ref<ClueApi.ClueVO>({} as ClueApi.ClueVO) // 绾跨储璇︽儏 -const getClue = async () => { - loading.value = true - try { - clue.value = await ClueApi.getClue(clueId.value) - await getOperateLog() - } finally { - loading.value = false - } -} - -/** 缂栬緫绾跨储 */ -const formRef = ref<InstanceType<typeof ClueForm>>() // 绾跨储琛ㄥ崟 Ref -const openForm = () => { - formRef.value?.open('update', clueId.value) -} - -/** 绾跨储杞Щ */ -const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // 绾跨储杞Щ琛ㄥ崟 ref -const transfer = () => { - transferFormRef.value?.open(clueId.value) -} - -/** 杞寲涓哄鎴� */ -const handleTransform = async () => { - await message.confirm(`纭畾灏嗐��${clue.value.name}銆戣浆鍖栦负瀹㈡埛鍚楋紵`) - await ClueApi.transformClue(clueId.value) - message.success(`杞寲瀹㈡埛銆�${clue.value.name}銆戞垚鍔焋) - await getClue() -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async () => { - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_CLUE, - bizId: clueId.value - }) - logList.value = data.list -} - -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(() => { - if (!params.id) { - message.warning('鍙傛暟閿欒锛岀嚎绱笉鑳戒负绌猴紒') - close() - return - } - clueId.value = params.id as unknown as number - getClue() -}) -</script> diff --git a/src/views/crm/clue/index.vue b/src/views/crm/clue/index.vue deleted file mode 100644 index f90d497..0000000 --- a/src/views/crm/clue/index.vue +++ /dev/null @@ -1,270 +0,0 @@ -<template> - <doc-alert title="銆愮嚎绱€�戠嚎绱㈢鐞�" url="https://doc.iocoder.cn/crm/clue/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="绾跨储鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ョ嚎绱㈠悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="杞寲鐘舵��" prop="transformStatus"> - <el-select v-model="queryParams.transformStatus" class="!w-240px"> - <el-option :value="false" label="鏈浆鍖�" /> - <el-option :value="true" label="宸茶浆鍖�" /> - </el-select> - </el-form-item> - <el-form-item label="鎵嬫満鍙�" prop="mobile"> - <el-input - v-model="queryParams.mobile" - placeholder="璇疯緭鍏ユ墜鏈哄彿" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐢佃瘽" prop="telephone"> - <el-input - v-model="queryParams.telephone" - placeholder="璇疯緭鍏ョ數璇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:clue:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['crm:clue:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="绾跨储鍚嶇О" align="center" prop="name" fixed="left" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column label="绾跨储鏉ユ簮" align="center" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - label="鏈�鍚庤窡杩涙椂闂�" - align="center" - prop="contactLastTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100" /> - <el-table-column - label="鏇存柊鏃堕棿" - align="center" - prop="updateTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column label="鎿嶄綔" align="center" min-width="110" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['crm:clue:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['crm:clue:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ClueForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ClueApi from '@/api/crm/clue' -import ClueForm from './ClueForm.vue' -import { TabsPaneContext } from 'element-plus' - -defineOptions({ name: 'CrmClue' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - name: null, - telephone: null, - mobile: null, - transformStatus: false -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ClueApi.getCluePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 鎵撳紑绾跨储璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmClueDetail', params: { id } }) -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ClueApi.deleteClue(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ClueApi.exportClue(queryParams) - download.excel(data, '绾跨储.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/contact/ContactForm.vue b/src/views/crm/contact/ContactForm.vue deleted file mode 100644 index ac749da..0000000 --- a/src/views/crm/contact/ContactForm.vue +++ /dev/null @@ -1,310 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="鑱旂郴浜哄鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ鍚�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - :disabled="formData.customerDefault" - v-model="formData.customerId" - placeholder="璇烽�夋嫨瀹㈡埛" - class="w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎵嬫満" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鐢佃瘽" prop="telephone"> - <el-input v-model="formData.telephone" placeholder="璇疯緭鍏ョ數璇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閭" prop="email"> - <el-input v-model="formData.email" placeholder="璇疯緭鍏ラ偖绠�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="寰俊" prop="wechat"> - <el-input v-model="formData.wechat" placeholder="璇疯緭鍏ュ井淇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="QQ" prop="qq"> - <el-input v-model="formData.qq" placeholder="璇疯緭鍏� QQ" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鑱屼綅" prop="post"> - <el-input v-model="formData.post" placeholder="璇疯緭鍏ヨ亴浣�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍏抽敭鍐崇瓥浜�" prop="master" style="width: 400px"> - <el-radio-group v-model="formData.master"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鎬у埆" prop="sex"> - <el-select v-model="formData.sex" placeholder="璇烽�夋嫨" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鐩村睘涓婄骇" prop="parentId"> - <el-select v-model="formData.parentId" placeholder="璇烽�夋嫨鐩村睘涓婄骇" class="w-1/1"> - <el-option - v-for="item in contactList" - :key="item.id" - :disabled="item.id == formData.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍦板潃" prop="areaId"> - <el-cascader - v-model="formData.areaId" - :options="areaList" - :props="defaultProps" - class="w-1/1" - clearable - filterable - placeholder="璇烽�夋嫨鍩庡競" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璇︾粏鍦板潃" prop="detailAddress"> - <el-input v-model="formData.detailAddress" placeholder="璇疯緭鍏ヨ缁嗗湴鍧�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="涓嬫鑱旂郴鏃堕棿" prop="contactNextTime"> - <el-date-picker - v-model="formData.contactNextTime" - placeholder="閫夋嫨涓嬫鑱旂郴鏃堕棿" - type="datetime" - value-format="x" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as ContactApi from '@/api/crm/contact' -import { DICT_TYPE, getBoolDictOptions, getIntDictOptions } from '@/utils/dict' -import * as UserApi from '@/api/system/user' -import * as CustomerApi from '@/api/crm/customer' -import * as AreaApi from '@/api/system/area' -import { defaultProps } from '@/utils/tree' -import { useUserStore } from '@/store/modules/user' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const areaList = ref([]) // 鍦板尯鍒楄〃 -const formData = ref({ - id: undefined, - name: undefined, - customerId: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - sex: undefined, - master: false, - post: undefined, - parentId: undefined, - remark: undefined, - businessId: undefined, - customerDefault: false -}) -const formRules = reactive({ - name: [{ required: true, message: '濮撳悕涓嶈兘涓虹┖', trigger: 'blur' }], - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const contactList = ref<ContactApi.ContactVO[]>([]) // 鑱旂郴浜哄垪琛� - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number, customerId?: number, businessId?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ContactApi.getContact(id) - } finally { - formLoading.value = false - } - } else { - if (customerId) { - formData.value.customerId = customerId - formData.value.customerDefault = true // 榛樿瀹㈡埛鐨勯�夋嫨锛屼笉鍏佽鍙� - } - // 鑷姩鍏宠仈 businessId 鍟嗘満缂栧彿 - if (businessId) { - formData.value.businessId = businessId - } - } - // 鑾峰緱鑱旂郴浜哄垪琛� - contactList.value = await ContactApi.getSimpleContactList() - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鑾峰緱鍦板尯鍒楄〃 - areaList.value = await AreaApi.getAreaTree() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ContactApi.ContactVO - if (formType.value === 'create') { - await ContactApi.createContact(data) - message.success(t('common.createSuccess')) - } else { - await ContactApi.updateContact(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - customerId: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - sex: undefined, - master: false, - post: undefined, - parentId: undefined, - remark: undefined, - businessId: undefined, - customerDefault: false - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/contact/components/ContactList.vue b/src/views/crm/contact/components/ContactList.vue deleted file mode 100644 index 1c12ca8..0000000 --- a/src/views/crm/contact/components/ContactList.vue +++ /dev/null @@ -1,185 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row justify="end"> - <el-button @click="openForm"> - <Icon class="mr-5px" icon="system-uicons:contacts" /> - 鍒涘缓鑱旂郴浜� - </el-button> - <el-button - v-if="queryParams.businessId" - v-hasPermi="['crm:contact:create-business']" - @click="openBusinessModal" - > - <Icon class="mr-5px" icon="ep:circle-plus" /> - 鍏宠仈 - </el-button> - <el-button - v-if="queryParams.businessId" - v-hasPermi="['crm:contact:delete-business']" - @click="deleteContactBusinessList" - > - <Icon class="mr-5px" icon="ep:remove" /> - 瑙i櫎鍏宠仈 - </el-button> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table - ref="contactRef" - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - > - <el-table-column v-if="queryParams.businessId" type="selection" width="55" /> - <el-table-column align="center" fixed="left" label="濮撳悕" prop="name"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鎵嬫満鍙�" prop="mobile" /> - <el-table-column align="center" label="鑱屼綅" prop="post" /> - <el-table-column align="center" label="鐩村睘涓婄骇" prop="parentName" /> - <el-table-column align="center" label="鏄惁鍏抽敭鍐崇瓥浜�" min-width="100" prop="master"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <ContactForm ref="formRef" @success="getList" /> - <!-- 鍏宠仈鍟嗘満閫夋嫨寮规 --> - <ContactListModal - v-if="customerId" - ref="contactModalRef" - :customer-id="customerId" - @success="createContactBusinessList" - /> -</template> -<script lang="ts" setup> -import * as ContactApi from '@/api/crm/contact' -import ContactForm from './../ContactForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { BizTypeEnum } from '@/api/crm/permission' -import ContactListModal from './ContactListModal.vue' - -defineOptions({ name: 'CrmContactList' }) -const props = defineProps<{ - bizType: number // 涓氬姟绫诲瀷 - bizId: number // 涓氬姟缂栧彿 - customerId?: number // 鐗规畩锛氬鎴风紪鍙凤紱鍦ㄣ�愬晢鏈恒�戣鎯呬腑锛屽彲浠ヤ紶閫掑鎴风紪鍙凤紝榛樿鏂板缓鐨勮仈绯讳汉鍏宠仈鍒拌瀹㈡埛 - businessId?: number // 鐗规畩锛氬晢鏈虹紪鍙凤紱鍦ㄣ�愬晢鏈恒�戣鎯呬腑锛屽彲浠ヤ紶閫掑晢鏈虹紪鍙凤紝榛樿鏂板缓鐨勮仈绯讳汉鍏宠仈鍒拌鍟嗘満 -}>() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - customerId: undefined as unknown, // 鍏佽 undefined + number - businessId: undefined as unknown // 鍏佽 undefined + number -}) -const message = useMessage() - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 缃┖鍙傛暟 - queryParams.customerId = undefined - // 鎵ц鏌ヨ - let data = { list: [], total: 0 } - switch (props.bizType) { - case BizTypeEnum.CRM_CUSTOMER: - queryParams.customerId = props.bizId - data = await ContactApi.getContactPageByCustomer(queryParams) - break - case BizTypeEnum.CRM_BUSINESS: - queryParams.businessId = props.bizId - data = await ContactApi.getContactPageByBusiness(queryParams) - break - default: - return - } - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 娣诲姞鎿嶄綔 */ -const formRef = ref() -const openForm = () => { - formRef.value.open('create', undefined, props.customerId, props.businessId) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑鑱旂郴浜轰笌鍟嗘満鐨勫叧鑱斿脊绐� */ -const contactModalRef = ref() -const openBusinessModal = () => { - contactModalRef.value.open() -} -const createContactBusinessList = async (contactIds: number[]) => { - const data = { - businessId: props.bizId, - contactIds: contactIds - } as ContactApi.ContactBusiness2ReqVO - contactRef.value.getSelectionRows().forEach((row: ContactApi.ContactVO) => { - data.contactIds.push(row.id) - }) - await ContactApi.createContactBusinessList2(data) - // 鍒锋柊鍒楄〃 - message.success('鍏宠仈鑱旂郴浜烘垚鍔�') - handleQuery() -} - -/** 瑙i櫎鑱旂郴浜轰笌鍟嗘満鐨勫叧鑱� */ -const contactRef = ref() -const deleteContactBusinessList = async () => { - const data = { - businessId: props.bizId, - contactIds: contactRef.value.getSelectionRows().map((row: ContactApi.ContactVO) => row.id) - } as ContactApi.ContactBusiness2ReqVO - if (data.contactIds.length === 0) { - return message.error('鏈�夋嫨鑱旂郴浜�') - } - await ContactApi.deleteContactBusinessList2(data) - // 鍒锋柊鍒楄〃 - message.success('鍙栧叧鑱旂郴浜烘垚鍔�') - handleQuery() -} - -/** 鐩戝惉鎵撳紑鐨� bizId + bizType锛屼粠鑰屽姞杞芥渶鏂扮殑鍒楄〃 */ -watch( - () => [props.bizId, props.bizType], - () => { - handleQuery() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/contact/components/ContactListModal.vue b/src/views/crm/contact/components/ContactListModal.vue deleted file mode 100644 index 8b655c1..0000000 --- a/src/views/crm/contact/components/ContactListModal.vue +++ /dev/null @@ -1,160 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍏宠仈鑱旂郴浜�"> - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="90px" - > - <el-form-item label="鑱旂郴浜哄悕绉�" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヨ仈绯讳汉鍚嶇О" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['crm:business:create']" type="primary" @click="openForm()"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table - ref="contactRef" - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - > - <el-table-column type="selection" width="55" /> - <el-table-column align="center" fixed="left" label="濮撳悕" prop="name"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鎵嬫満鍙�" prop="mobile" /> - <el-table-column align="center" label="鑱屼綅" prop="post" /> - <el-table-column align="center" label="鐩村睘涓婄骇" prop="parentName" /> - <el-table-column align="center" label="鏄惁鍏抽敭鍐崇瓥浜�" min-width="100" prop="master"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <ContactForm ref="formRef" @success="getList" /> - </Dialog> -</template> -<script lang="ts" setup> -import * as ContactApi from '@/api/crm/contact' -import ContactForm from '../ContactForm.vue' -import { DICT_TYPE } from '@/utils/dict' - -const message = useMessage() // 娑堟伅寮圭獥 -const props = defineProps<{ - customerId: number -}>() -defineOptions({ name: 'ContactListModal' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - customerId: props.customerId -}) - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - queryParams.customerId = props.customerId // 瑙e喅 props.customerId 娌℃洿鏂板埌 queryParams 涓婄殑闂 - await getList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ContactApi.getContactPageByCustomer(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞鎿嶄綔 */ -const formRef = ref() -const openForm = () => { - formRef.value.open('create') -} - -/** 鍏宠仈鑱旂郴浜烘彁浜� */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const contactRef = ref() -const submitForm = async () => { - const contactIds = contactRef.value.getSelectionRows().map((row: ContactApi.ContactVO) => row.id) - if (contactIds.length === 0) { - return message.error('鏈�夋嫨鑱旂郴浜�') - } - dialogVisible.value = false - emit('success', contactIds, contactRef.value.getSelectionRows()) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} -</script> diff --git a/src/views/crm/contact/detail/ContactDetailsHeader.vue b/src/views/crm/contact/detail/ContactDetailsHeader.vue deleted file mode 100644 index 12fb3bc..0000000 --- a/src/views/crm/contact/detail/ContactDetailsHeader.vue +++ /dev/null @@ -1,33 +0,0 @@ -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ contact.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ contact.customerName }}</el-descriptions-item> - <el-descriptions-item label="鑱屽姟">{{ contact.post }}</el-descriptions-item> - <el-descriptions-item label="鎵嬫満">{{ contact.mobile }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(contact.createTime) }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ContactApi from '@/api/crm/contact' -import { formatDate } from '@/utils/formatTime' - -const { contact } = defineProps<{ contact: ContactApi.ContactVO }>() -</script> diff --git a/src/views/crm/contact/detail/ContactDetailsInfo.vue b/src/views/crm/contact/detail/ContactDetailsInfo.vue deleted file mode 100644 index 9e8bfff..0000000 --- a/src/views/crm/contact/detail/ContactDetailsInfo.vue +++ /dev/null @@ -1,69 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="濮撳悕">{{ contact.name }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ contact.customerName }}</el-descriptions-item> - <el-descriptions-item label="鎵嬫満">{{ contact.mobile }}</el-descriptions-item> - <el-descriptions-item label="鐢佃瘽">{{ contact.telephone }}</el-descriptions-item> - <el-descriptions-item label="閭">{{ contact.email }}</el-descriptions-item> - <el-descriptions-item label="QQ">{{ contact.qq }}</el-descriptions-item> - <el-descriptions-item label="寰俊">{{ contact.wechat }}</el-descriptions-item> - <el-descriptions-item label="鍦板潃"> - {{ contact.areaName }} {{ contact.detailAddress }} - </el-descriptions-item> - <el-descriptions-item label="鑱屽姟">{{ contact.post }}</el-descriptions-item> - <el-descriptions-item label="鐩村睘涓婄骇">{{ contact.parentName }}</el-descriptions-item> - <el-descriptions-item label="鍏抽敭鍐崇瓥浜�"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="contact.master" /> - </el-descriptions-item> - <el-descriptions-item label="鎬у埆"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="contact.sex" /> - </el-descriptions-item> - <el-descriptions-item label="涓嬫鑱旂郴鏃堕棿"> - {{ formatDate(contact.contactNextTime) }} - </el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ contact.remark }}</el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�">{{ contact.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涜褰�"> - {{ contact.contactLastContent }} - </el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涙椂闂�"> - {{ formatDate(contact.contactLastTime) }} - </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�">{{ contact.creatorName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(contact.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(contact.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ContactApi from '@/api/crm/contact' -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' - -const { contact } = defineProps<{ - contact: ContactApi.ContactVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['basicInfo', 'systemInfo']) -</script> diff --git a/src/views/crm/contact/detail/index.vue b/src/views/crm/contact/detail/index.vue deleted file mode 100644 index 7989d56..0000000 --- a/src/views/crm/contact/detail/index.vue +++ /dev/null @@ -1,121 +0,0 @@ -<template> - <ContactDetailsHeader v-loading="loading" :contact="contact"> - <el-button v-if="permissionListRef?.validateWrite" @click="openForm('update', contact.id)"> - 缂栬緫 - </el-button> - <el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transfer"> - 杞Щ - </el-button> - </ContactDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璺熻繘璁板綍"> - <FollowUpList :biz-id="contactId" :biz-type="BizTypeEnum.CRM_CONTACT" /> - </el-tab-pane> - <el-tab-pane label="璇︾粏璧勬枡"> - <ContactDetailsInfo :contact="contact" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="contact.id!" - :biz-type="BizTypeEnum.CRM_CONTACT" - :show-action="true" - @quit-team="close" - /> - </el-tab-pane> - <el-tab-pane label="鍟嗘満" lazy> - <BusinessList - :biz-id="contact.id!" - :biz-type="BizTypeEnum.CRM_CONTACT" - :contact-id="contact.id" - :customer-id="contact.customerId" - /> - </el-tab-pane> - </el-tabs> - </el-col> - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ContactForm ref="formRef" @success="getContact" /> - <CrmTransferForm ref="transferFormRef" :biz-type="BizTypeEnum.CRM_CONTACT" @success="close" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as ContactApi from '@/api/crm/contact' -import ContactDetailsHeader from '@/views/crm/contact/detail/ContactDetailsHeader.vue' -import ContactDetailsInfo from '@/views/crm/contact/detail/ContactDetailsInfo.vue' -import BusinessList from '@/views/crm/business/components/BusinessList.vue' // 鍟嗘満鍒楄〃 -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import { BizTypeEnum } from '@/api/crm/permission' -import { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' -import ContactForm from '@/views/crm/contact/ContactForm.vue' -import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue' -import FollowUpList from '@/views/crm/followup/index.vue' - -defineOptions({ name: 'CrmContactDetail' }) - -const message = useMessage() - -const contactId = ref(0) // 绾跨储缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const contact = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) // 鑱旂郴浜鸿鎯� -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const getContact = async () => { - loading.value = true - try { - contact.value = await ContactApi.getContact(contactId.value) - await getOperateLog(contactId.value) - } finally { - loading.value = false - } -} - -/** 缂栬緫 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鑱旂郴浜鸿浆绉� */ -const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // 鑱旂郴浜鸿浆绉昏〃鍗� ref -const transfer = () => { - transferFormRef.value?.open(contact.value.id) -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (contactId: number) => { - if (!contactId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_CONTACT, - bizId: contactId - }) - logList.value = data.list -} - -/** 鍏抽棴绐楀彛 */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(async () => { - if (!params.id) { - message.warning('鍙傛暟閿欒锛岃仈绯讳汉涓嶈兘涓虹┖锛�') - close() - return - } - contactId.value = params.id as unknown as number - await getContact() -}) -</script> diff --git a/src/views/crm/contact/index.vue b/src/views/crm/contact/index.vue deleted file mode 100644 index ec26f1e..0000000 --- a/src/views/crm/contact/index.vue +++ /dev/null @@ -1,332 +0,0 @@ -<template> - <doc-alert title="銆愬鎴枫�戝鎴风鐞嗐�佸叕娴峰鎴�" url="https://doc.iocoder.cn/crm/customer/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - class="!w-240px" - clearable - lable-key="name" - placeholder="璇烽�夋嫨瀹㈡埛" - value-key="id" - @keyup.enter="handleQuery" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id!" - /> - </el-select> - </el-form-item> - <el-form-item label="濮撳悕" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ鍚�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵嬫満鍙�" prop="mobile"> - <el-input - v-model="queryParams.mobile" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ墜鏈哄彿" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鐢佃瘽" prop="telephone"> - <el-input - v-model="queryParams.telephone" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ョ數璇�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="寰俊" prop="wechat"> - <el-input - v-model="queryParams.wechat" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ井淇�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鐢靛瓙閭" prop="email"> - <el-input - v-model="queryParams.email" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ョ數瀛愰偖绠�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['crm:contact:create']" type="primary" @click="openForm('create')"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['crm:contact:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鑱旂郴浜哄鍚�" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鎵嬫満" prop="mobile" width="120" /> - <el-table-column align="center" label="鐢佃瘽" prop="telephone" width="130" /> - <el-table-column align="center" label="閭" prop="email" width="180" /> - <el-table-column align="center" label="鑱屼綅" prop="post" width="120" /> - <el-table-column align="center" label="鍦板潃" prop="detailAddress" width="120" /> - <el-table-column align="center" label="鍏抽敭鍐崇瓥浜�" prop="master" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" /> - </template> - </el-table-column> - <el-table-column align="center" label="鐩村睘涓婄骇" prop="parentName" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.parentId)"> - {{ scope.row.parentName }} - </el-link> - </template> - </el-table-column> - <el-table-column label="鍦板潃" align="center" prop="detailAddress" width="180" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="鎬у埆" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="200"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:contact:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:contact:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ContactForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ContactApi from '@/api/crm/contact' -import ContactForm from './ContactForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import * as CustomerApi from '@/api/crm/customer' -import { TabsPaneContext } from 'element-plus' - -defineOptions({ name: 'CrmContact' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - mobile: undefined, - telephone: undefined, - email: undefined, - customerId: undefined, - name: undefined, - wechat: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ContactApi.getContactPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ContactApi.deleteContact(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ContactApi.exportContact(queryParams) - download.excel(data, '鑱旂郴浜�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - customerList.value = await CustomerApi.getCustomerSimpleList() -}) -</script> diff --git a/src/views/crm/contract/ContractForm.vue b/src/views/crm/contract/ContractForm.vue deleted file mode 100644 index 9c5b2c6..0000000 --- a/src/views/crm/contract/ContractForm.vue +++ /dev/null @@ -1,369 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="1280"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="120px" - > - <el-row> - <el-col :span="8"> - <el-form-item label="鍚堝悓缂栧彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍚堝悓鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悎鍚屽悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="8"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - v-model="formData.customerId" - placeholder="璇烽�夋嫨瀹㈡埛" - class="w-1/1" - @change="handleCustomerChange" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍟嗘満鍚嶇О" prop="businessId"> - <el-select - @change="handleBusinessChange" - :disabled="!formData.customerId" - v-model="formData.businessId" - class="w-1/1" - > - <el-option - v-for="item in getBusinessOptions" - :key="item.id" - :label="item.name" - :value="item.id!" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="8"> - <el-form-item label="涓嬪崟鏃ユ湡" prop="orderDate"> - <el-date-picker - v-model="formData.orderDate" - placeholder="閫夋嫨涓嬪崟鏃ユ湡" - type="date" - value-format="x" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="寮�濮嬫椂闂�" prop="startTime"> - <el-date-picker - v-model="formData.startTime" - placeholder="閫夋嫨寮�濮嬫椂闂�" - type="date" - value-format="x" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撴潫鏃堕棿" prop="endTime"> - <el-date-picker - v-model="formData.endTime" - placeholder="閫夋嫨缁撴潫鏃堕棿" - type="date" - value-format="x" - class="!w-1/1" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="8"> - <el-form-item label="鍏徃绛剧害浜�" prop="signUserId"> - <el-select v-model="formData.signUserId" class="w-1/1"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id!" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛绛剧害浜�" prop="signContactId"> - <el-select - v-model="formData.signContactId" - :disabled="!formData.customerId" - class="w-1/1" - > - <el-option - v-for="item in getContactOptions" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="浜у搧娓呭崟" name="product"> - <ContractProductForm - ref="productFormRef" - :products="formData.products" - :disabled="disabled" - /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row> - <el-col :span="8"> - <el-form-item label="浜у搧鎬婚噾棰�" prop="totalProductPrice"> - <el-input - disabled - v-model="formData.totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏁村崟鎶樻墸锛�%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - placeholder="璇疯緭鍏ユ暣鍗曟姌鎵�" - controls-position="right" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鎶樻墸鍚庨噾棰�" prop="totalPrice"> - <el-input - disabled - v-model="formData.totalPrice" - placeholder="璇疯緭鍏ュ晢鏈洪噾棰�" - :formatter="erpPriceTableColumnFormattere" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">淇濆瓨</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import * as ContractApi from '@/api/crm/contract' -import * as UserApi from '@/api/system/user' -import * as ContactApi from '@/api/crm/contact' -import * as BusinessApi from '@/api/crm/business' -import { erpPriceMultiply, erpPriceTableColumnFormatter } from '@/utils' -import { useUserStore } from '@/store/modules/user' -import ContractProductForm from '@/views/crm/contract/components/ContractProductForm.vue' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - no: undefined, - name: undefined, - customerId: undefined, - businessId: undefined, - orderDate: undefined, - startTime: undefined, - endTime: undefined, - signUserId: undefined, - signContactId: undefined, - ownerUserId: undefined, - discountPercent: 0, - totalProductPrice: undefined, - remark: undefined, - products: [] -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚堝悓鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - orderDate: [{ required: true, message: '涓嬪崟鏃ユ湡涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const customerList = ref([]) // 瀹㈡埛鍒楄〃鐨勬暟鎹� -const businessList = ref<BusinessApi.BusinessVO[]>([]) -const contactList = ref<ContactApi.ContactVO[]>([]) - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('product') -const productFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalProductPrice = val.products.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null - ? erpPriceMultiply(totalProductPrice, val.discountPercent / 100.0) - : 0 - const totalPrice = totalProductPrice - discountPrice - // 璧嬪�� - formData.value.totalProductPrice = totalProductPrice - formData.value.totalPrice = totalPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ContractApi.getContract(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } - // 鑾峰彇鑱旂郴浜� - contactList.value = await ContactApi.getSimpleContactList() - // 鑾峰緱鍟嗘満鍒楄〃 - businessList.value = await BusinessApi.getSimpleBusinessList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - productFormRef.value.validate() - try { - const data = unref(formData.value) as unknown as ContractApi.ContractVO - if (formType.value === 'create') { - await ContractApi.createContract(data) - message.success(t('common.createSuccess')) - } else { - await ContractApi.updateContract(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - no: undefined, - name: undefined, - customerId: undefined, - businessId: undefined, - orderDate: undefined, - startTime: undefined, - endTime: undefined, - signUserId: undefined, - signContactId: undefined, - ownerUserId: undefined, - discountPercent: 0, - totalProductPrice: undefined, - remark: undefined, - products: [] - } - formRef.value?.resetFields() -} - -/** 澶勭悊鍒囨崲瀹㈡埛 */ -const handleCustomerChange = () => { - formData.value.businessId = undefined - formData.value.signContactId = undefined - formData.value.products = [] -} - -/** 澶勭悊鍟嗘満鍙樺寲 */ -const handleBusinessChange = async (businessId: number) => { - const business = await BusinessApi.getBusiness(businessId) - business.products.forEach((item) => { - item.contractPrice = item.businessPrice - }) - formData.value.products = business.products -} - -/** 鍔ㄦ�佽幏鍙栧鎴疯仈绯讳汉 */ -const getContactOptions = computed(() => - contactList.value.filter((item) => item.customerId == formData.value.customerId) -) -/** 鍔ㄦ�佽幏鍙栧晢鏈� */ -const getBusinessOptions = computed(() => - businessList.value.filter((item) => item.customerId == formData.value.customerId) -) -</script> diff --git a/src/views/crm/contract/components/ContractList.vue b/src/views/crm/contract/components/ContractList.vue deleted file mode 100644 index f693c9a..0000000 --- a/src/views/crm/contract/components/ContractList.vue +++ /dev/null @@ -1,136 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row justify="end"> - <el-button @click="openForm"> - <Icon class="mr-5px" icon="clarity:contract-line" /> - 鍒涘缓鍚堝悓 - </el-button> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍚堝悓鍚嶇О" fixed="left" align="center" prop="name"> - <template #default="scope"> - <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column label="鍚堝悓缂栧彿" align="center" prop="no" /> - <el-table-column label="瀹㈡埛鍚嶇О" align="center" prop="customerName" /> - <el-table-column - label="鍚堝悓閲戦锛堝厓锛�" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="寮�濮嬫椂闂�" - align="center" - prop="startTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="缁撴潫鏃堕棿" - align="center" - prop="endTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column align="center" label="鐘舵��" prop="auditStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <ContractForm ref="formRef" @success="getList" /> -</template> -<script setup lang="ts"> -import * as ContractApi from '@/api/crm/contract' -import ContractForm from './../ContractForm.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import { dateFormatter } from '@/utils/formatTime' -import { DICT_TYPE } from '@/utils/dict' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CrmContractList' }) -const props = defineProps<{ - bizType: number // 涓氬姟绫诲瀷 - bizId: number // 涓氬姟缂栧彿 -}>() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - customerId: undefined as unknown // 鍏佽 undefined + number -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 缃┖鍙傛暟 - queryParams.customerId = undefined - // 鎵ц鏌ヨ - let data = { list: [], total: 0 } - switch (props.bizType) { - case BizTypeEnum.CRM_CUSTOMER: - queryParams.customerId = props.bizId - data = await ContractApi.getContractPageByCustomer(queryParams) - break - case BizTypeEnum.CRM_BUSINESS: - queryParams.businessId = props.bizId - data = await ContractApi.getContractPageByBusiness(queryParams) - break - default: - return - } - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 娣诲姞 */ -const formRef = ref() -const openForm = () => { - formRef.value.open('create') -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 鐩戝惉鎵撳紑鐨� bizId + bizType锛屼粠鑰屽姞杞芥渶鏂扮殑鍒楄〃 */ -watch( - () => [props.bizId, props.bizType], - () => { - handleQuery() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/contract/components/ContractProductForm.vue b/src/views/crm/contract/components/ContractProductForm.vue deleted file mode 100644 index c33b996..0000000 --- a/src/views/crm/contract/components/ContractProductForm.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productNo" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" /> - </template> - </el-table-column> - <el-table-column label="浠锋牸锛堝厓锛�" min-width="120"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍞环锛堝厓锛�" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.contractPrice`" class="mb-0px!"> - <el-input-number - v-model="row.contractPrice" - controls-position="right" - :min="0.001" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣" prop="totalPrice" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import * as ProductApi from '@/api/crm/product' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import { DICT_TYPE } from '@/utils/dict' - -const props = defineProps<{ - products: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - contractPrice: [{ required: true, message: '鍚堝悓浠锋牸涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductApi.ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃骇鍝侀」 */ -watch( - () => props.products, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - if (item.contractPrice != null && item.count != null) { - item.totalPrice = erpPriceMultiply(item.contractPrice, item.count) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnit: undefined, // 浜у搧鍗曚綅 - productNo: undefined, // 浜у搧鏉$爜 - productPrice: undefined, // 浜у搧浠锋牸 - contractPrice: undefined, - count: 1 - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnit = product.unit - row.productNo = product.no - row.productPrice = product.price - row.contractPrice = product.price - } -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() -}) -</script> diff --git a/src/views/crm/contract/config/index.vue b/src/views/crm/contract/config/index.vue deleted file mode 100644 index be654f7..0000000 --- a/src/views/crm/contract/config/index.vue +++ /dev/null @@ -1,103 +0,0 @@ -<template> - <doc-alert title="銆愬悎鍚屻�戝悎鍚岀鐞嗐�佸悎鍚屾彁閱�" url="https://doc.iocoder.cn/crm/contract/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="160px" - v-loading="formLoading" - > - <el-card shadow="never"> - <!-- 鎿嶄綔 --> - <template #header> - <div class="flex items-center justify-between"> - <CardTitle title="鍚堝悓閰嶇疆璁剧疆" /> - <el-button type="primary" @click="onSubmit" v-hasPermi="['crm:contract-config:update']"> - 淇濆瓨 - </el-button> - </div> - </template> - <!-- 琛ㄥ崟 --> - <el-form-item label="鎻愬墠鎻愰啋璁剧疆" prop="notifyEnabled"> - <el-radio-group - v-model="formData.notifyEnabled" - @change="changeNotifyEnable" - class="ml-4" - > - <el-radio :label="false" size="large">涓嶆彁閱�</el-radio> - <el-radio :label="true" size="large">鎻愰啋</el-radio> - </el-radio-group> - </el-form-item> - <div v-if="formData.notifyEnabled"> - <el-form-item> - 鎻愬墠 <el-input-number class="mx-2" v-model="formData.notifyDays" /> 澶╂彁閱� - </el-form-item> - </div> - </el-card> - </el-form> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ContractConfigApi from '@/api/crm/contract/config' -import { CardTitle } from '@/components/Card' - -defineOptions({ name: 'CrmContractConfig' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const formLoading = ref(false) -const formData = ref({ - notifyEnabled: false, - notifyDays: undefined -}) -const formRules = reactive({}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鑾峰彇閰嶇疆 */ -const getConfig = async () => { - try { - formLoading.value = true - const data = await ContractConfigApi.getContractConfig() - if (data === null) { - return - } - formData.value = data - } finally { - formLoading.value = false - } -} - -/** 鎻愪氦閰嶇疆 */ -const onSubmit = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as ContractConfigApi.ContractConfigVO - await ContractConfigApi.saveContractConfig(data) - message.success(t('common.updateSuccess')) - await getConfig() - formLoading.value = false - } finally { - formLoading.value = false - } -} - -/** 鏇存敼鎻愬墠鎻愰啋璁剧疆 */ -const changeNotifyEnable = () => { - if (!formData.value.notifyEnabled) { - formData.value.notifyDays = undefined - } -} - -onMounted(() => { - getConfig() -}) -</script> diff --git a/src/views/crm/contract/detail/ContractDetailsHeader.vue b/src/views/crm/contract/detail/ContractDetailsHeader.vue deleted file mode 100644 index 9cfbfc7..0000000 --- a/src/views/crm/contract/detail/ContractDetailsHeader.vue +++ /dev/null @@ -1,45 +0,0 @@ -<!-- 鍚堝悓璇︽儏澶撮儴缁勪欢--> -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ contract.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ contract.customerName }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓閲戦锛堝厓锛�"> - {{ erpPriceInputFormatter(contract.totalPrice) }} - </el-descriptions-item> - <el-descriptions-item label="涓嬪崟鏃堕棿"> - {{ formatDate(contract.orderDate) }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴閲戦锛堝厓锛�"> - {{ erpPriceInputFormatter(contract.totalReceivablePrice) }} - </el-descriptions-item> - <el-descriptions-item label="璐熻矗浜�"> - {{ contract.ownerUserName }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ContractApi from '@/api/crm/contract' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -defineOptions({ name: 'ContractDetailsHeader' }) -defineProps<{ contract: ContractApi.ContractVO }>() -</script> diff --git a/src/views/crm/contract/detail/ContractDetailsInfo.vue b/src/views/crm/contract/detail/ContractDetailsInfo.vue deleted file mode 100644 index 73aa144..0000000 --- a/src/views/crm/contract/detail/ContractDetailsInfo.vue +++ /dev/null @@ -1,76 +0,0 @@ -<!-- 鍚堝悓璇︽儏缁勪欢 --> -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="contractInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="鍚堝悓缂栧彿">{{ contract.no }}</el-descriptions-item> - <el-descriptions-item label="鍚堝悓鍚嶇О">{{ contract.name }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ contract.customerName }}</el-descriptions-item> - <el-descriptions-item label="鍟嗘満鍚嶇О">{{ contract.businessName }}</el-descriptions-item> - <el-descriptions-item label="鍚堝悓閲戦锛堝厓锛�"> - {{ erpPriceInputFormatter(contract.totalPrice) }} - </el-descriptions-item> - <el-descriptions-item label="涓嬪崟鏃堕棿"> - {{ formatDate(contract.orderDate) }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓寮�濮嬫椂闂�"> - {{ formatDate(contract.startTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓缁撴潫鏃堕棿"> - {{ formatDate(contract.endTime) }} - </el-descriptions-item> - <el-descriptions-item label="瀹㈡埛绛剧害浜�"> - {{ contract.signContactName }} - </el-descriptions-item> - <el-descriptions-item label="鍏徃绛剧害浜�"> - {{ contract.signUserName }} - </el-descriptions-item> - <el-descriptions-item label="澶囨敞"> - {{ contract.remark }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓鐘舵��"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="contract.auditStatus" /> - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�">{{ contract.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涙椂闂�"> - {{ formatDate(contract.contactLastTime) }} - </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�">{{ contract.creatorName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(contract.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(contract.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ContractApi from '@/api/crm/contract' -import { formatDate } from '@/utils/formatTime' -import { DICT_TYPE } from '@/utils/dict' -import { erpPriceInputFormatter } from '@/utils' - -defineOptions({ name: 'ContractDetailsInfo' }) -defineProps<{ - contract: ContractApi.ContractVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['contractInfo', 'systemInfo']) -</script> diff --git a/src/views/crm/contract/detail/ContractProductList.vue b/src/views/crm/contract/detail/ContractProductList.vue deleted file mode 100644 index ea23d17..0000000 --- a/src/views/crm/contract/detail/ContractProductList.vue +++ /dev/null @@ -1,66 +0,0 @@ -<template> - <ContentWrap> - <el-table :data="contract.products" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column - align="center" - label="浜у搧鍚嶇О" - fixed="left" - prop="productName" - min-width="160" - > - <template #default="scope"> - {{ scope.row.productName }} - </template> - </el-table-column> - <el-table-column label="浜у搧鏉$爜" align="center" prop="productNo" min-width="120" /> - <el-table-column align="center" label="浜у搧鍗曚綅" prop="productUnit" min-width="160"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" /> - </template> - </el-table-column> - <el-table-column - label="浜у搧浠锋牸锛堝厓锛�" - align="center" - prop="productPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚堝悓浠锋牸锛堝厓锛�" - align="center" - prop="contractPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="鏁伴噺" - prop="count" - min-width="100px" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚堣閲戦锛堝厓锛�" - align="center" - prop="totalPrice" - min-width="140" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <el-row class="mt-10px" justify="end"> - <el-col :span="3"> 鏁村崟鎶樻墸锛歿{ erpPriceInputFormatter(contract.discountPercent) }}% </el-col> - <el-col :span="4"> - 浜у搧鎬婚噾棰濓細{{ erpPriceInputFormatter(contract.totalProductPrice) }} 鍏� - </el-col> - </el-row> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ContractApi from '@/api/crm/contract' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { DICT_TYPE } from '@/utils/dict' - -const { contract } = defineProps<{ - contract: ContractApi.ContractVO -}>() -</script> diff --git a/src/views/crm/contract/detail/index.vue b/src/views/crm/contract/detail/index.vue deleted file mode 100644 index 1369a35..0000000 --- a/src/views/crm/contract/detail/index.vue +++ /dev/null @@ -1,139 +0,0 @@ -<!-- 鍚堝悓璇︽儏椤甸潰缁勪欢--> -<template> - <ContractDetailsHeader v-loading="loading" :contract="contract"> - <el-button v-if="permissionListRef?.validateWrite" @click="openForm('update', contract.id)"> - 缂栬緫 - </el-button> - <el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transferContract"> - 杞Щ - </el-button> - </ContractDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璺熻繘璁板綍"> - <FollowUpList :biz-id="contract.id" :biz-type="BizTypeEnum.CRM_CONTRACT" /> - </el-tab-pane> - <el-tab-pane label="鍩烘湰淇℃伅"> - <ContractDetailsInfo :contract="contract" /> - </el-tab-pane> - <el-tab-pane label="浜у搧"> - <ContractProductList :contract="contract" /> - </el-tab-pane> - <el-tab-pane label="鍥炴"> - <ReceivablePlanList - :contract-id="contract.id!" - :customer-id="contract.customerId" - @create-receivable="createReceivable" - /> - <ReceivableList - ref="receivableListRef" - :contract-id="contract.id!" - :customer-id="contract.customerId" - /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="contract.id!" - :biz-type="BizTypeEnum.CRM_CONTRACT" - :show-action="!permissionListRef?.isPool || false" - @quit-team="close" - /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ContractForm ref="formRef" @success="getContractData" /> - <CrmTransferForm ref="transferFormRef" :biz-type="BizTypeEnum.CRM_CONTRACT" @success="close" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import { OperateLogVO } from '@/api/system/operatelog' -import * as ContractApi from '@/api/crm/contract' -import ContractDetailsInfo from './ContractDetailsInfo.vue' -import ContractDetailsHeader from './ContractDetailsHeader.vue' -import ContractProductList from './ContractProductList.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import { getOperateLogPage } from '@/api/crm/operateLog' -import ContractForm from '@/views/crm/contract/ContractForm.vue' -import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue' -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' -import FollowUpList from '@/views/crm/followup/index.vue' -import ReceivableList from '@/views/crm/receivable/components/ReceivableList.vue' -import ReceivablePlanList from '@/views/crm/receivable/plan/components/ReceivablePlanList.vue' - -defineOptions({ name: 'CrmContractDetail' }) -const props = defineProps<{ id?: number }>() - -const route = useRoute() -const message = useMessage() -const contractId = ref(0) // 缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const contract = ref<ContractApi.ContractVO>({} as ContractApi.ContractVO) // 璇︽儏 -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 缂栬緫 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鑾峰彇璇︽儏 */ -const getContractData = async () => { - loading.value = true - try { - contract.value = await ContractApi.getContract(contractId.value) - await getOperateLog(contractId.value) - } finally { - loading.value = false - } -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (contractId: number) => { - if (!contractId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_CONTRACT, - bizId: contractId - }) - logList.value = data.list -} - -/** 浠庡洖娆捐鍒掑垱寤哄洖娆� */ -const receivableListRef = ref<InstanceType<typeof ReceivableList>>() // 鍥炴鍒楄〃 Ref -const createReceivable = (planData: any) => { - receivableListRef.value?.createReceivable(planData) -} - -/** 杞Щ */ -const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // 鍚堝悓杞Щ琛ㄥ崟 ref -const transferContract = () => { - transferFormRef.value?.open(contract.value.id) -} - -/** 鍏抽棴 */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -onMounted(async () => { - const id = props.id || route.params.id - if (!id) { - message.warning('鍙傛暟閿欒锛屽悎鍚屼笉鑳戒负绌猴紒') - close() - return - } - contractId.value = id as unknown as number - await getContractData() -}) -</script> diff --git a/src/views/crm/contract/index.vue b/src/views/crm/contract/index.vue deleted file mode 100644 index 0c9d728..0000000 --- a/src/views/crm/contract/index.vue +++ /dev/null @@ -1,398 +0,0 @@ -<template> - <doc-alert title="銆愬悎鍚屻�戝悎鍚岀鐞嗐�佸悎鍚屾彁閱�" url="https://doc.iocoder.cn/crm/contract/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍚堝悓缂栧彿" prop="no"> - <el-input - v-model="queryParams.no" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ悎鍚岀紪鍙�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍚堝悓鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ悎鍚屽悕绉�" - @keyup.enter="handleQuery" - /> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - class="!w-240px" - clearable - lable-key="name" - placeholder="璇烽�夋嫨瀹㈡埛" - value-key="id" - @keyup.enter="handleQuery" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id!" - /> - </el-select> - </el-form-item> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['crm:contract:create']" type="primary" @click="openForm('create')"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['crm:contract:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鍚堝悓缂栧彿" prop="no" width="180" /> - <el-table-column align="center" fixed="left" label="鍚堝悓鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍟嗘満鍚嶇О" prop="businessName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openBusinessDetail(scope.row.businessId)" - > - {{ scope.row.businessName }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="鍚堝悓閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="涓嬪崟鏃堕棿" - prop="orderDate" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓寮�濮嬫椂闂�" - prop="startTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="鍚堝悓缁撴潫鏃堕棿" - prop="endTime" - width="120" - :formatter="dateFormatter2" - /> - <el-table-column align="center" label="瀹㈡埛绛剧害浜�" prop="contactName" width="130"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openContactDetail(scope.row.signContactId)" - > - {{ scope.row.signContactName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍏徃绛剧害浜�" prop="signUserName" width="130" /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - align="center" - label="宸插洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - align="center" - label="鏈洖娆鹃噾棰濓紙鍏冿級" - prop="totalReceivablePrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - > - <template #default="scope"> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.totalReceivablePrice) }} - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鍚堝悓鐘舵��" prop="auditStatus" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - <el-table-column fixed="right" label="鎿嶄綔" width="250"> - <template #default="scope"> - <el-button - v-if="scope.row.auditStatus === 0" - v-hasPermi="['crm:contract:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-if="scope.row.auditStatus === 0" - v-hasPermi="['crm:contract:update']" - link - type="primary" - @click="handleSubmit(scope.row)" - > - 鎻愪氦瀹℃牳 - </el-button> - <el-button - v-else - link - v-hasPermi="['crm:contract:update']" - type="primary" - @click="handleProcessDetail(scope.row)" - > - 鏌ョ湅瀹℃壒 - </el-button> - <el-button - v-hasPermi="['crm:contract:query']" - link - type="primary" - @click="openDetail(scope.row.id)" - > - 璇︽儏 - </el-button> - <el-button - v-hasPermi="['crm:contract:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ContractForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ContractApi from '@/api/crm/contract' -import ContractForm from './ContractForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import * as CustomerApi from '@/api/crm/customer' -import { TabsPaneContext } from 'element-plus' - -defineOptions({ name: 'CrmContract' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - name: null, - customerId: null, - orderDate: [], - no: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ContractApi.getContractPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ContractApi.deleteContract(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ContractApi.exportContract(queryParams) - download.excel(data, '鍚堝悓.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鎻愪氦瀹℃牳 **/ -const handleSubmit = async (row: ContractApi.ContractVO) => { - await message.confirm(`鎮ㄧ‘瀹氭彁浜ゃ��${row.name}銆戝鏍稿悧锛焋) - await ContractApi.submitContract(row.id) - message.success('鎻愪氦瀹℃牳鎴愬姛锛�') - await getList() -} - -/** 鏌ョ湅瀹℃壒 */ -const handleProcessDetail = (row: ContractApi.ContractVO) => { - push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }) -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const openContactDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑鍟嗘満璇︽儏 */ -const openBusinessDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - customerList.value = await CustomerApi.getCustomerSimpleList() -}) -</script> diff --git a/src/views/crm/customer/CustomerForm.vue b/src/views/crm/customer/CustomerForm.vue deleted file mode 100644 index 8286971..0000000 --- a/src/views/crm/customer/CustomerForm.vue +++ /dev/null @@ -1,259 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ鎴峰悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鏉ユ簮" prop="source"> - <el-select v-model="formData.source" placeholder="璇烽�夋嫨瀹㈡埛鏉ユ簮" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鎵嬫満" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鐢佃瘽" prop="telephone"> - <el-input v-model="formData.telephone" placeholder="璇疯緭鍏ョ數璇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閭" prop="email"> - <el-input v-model="formData.email" placeholder="璇疯緭鍏ラ偖绠�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="寰俊" prop="wechat"> - <el-input v-model="formData.wechat" placeholder="璇疯緭鍏ュ井淇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="QQ" prop="qq"> - <el-input v-model="formData.qq" placeholder="璇疯緭鍏� QQ" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛琛屼笟" prop="industryId"> - <el-select v-model="formData.industryId" placeholder="璇烽�夋嫨瀹㈡埛琛屼笟" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="瀹㈡埛绾у埆" prop="level"> - <el-select v-model="formData.level" placeholder="璇烽�夋嫨瀹㈡埛绾у埆" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍦板潃" prop="areaId"> - <el-cascader - v-model="formData.areaId" - :options="areaList" - :props="defaultProps" - class="w-1/1" - clearable - filterable - placeholder="璇烽�夋嫨鍩庡競" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璇︾粏鍦板潃" prop="detailAddress"> - <el-input v-model="formData.detailAddress" placeholder="璇疯緭鍏ヨ缁嗗湴鍧�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="涓嬫鑱旂郴鏃堕棿" prop="contactNextTime"> - <el-date-picker - v-model="formData.contactNextTime" - placeholder="閫夋嫨涓嬫鑱旂郴鏃堕棿" - type="datetime" - value-format="x" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as CustomerApi from '@/api/crm/customer' -import * as AreaApi from '@/api/system/area' -import { defaultProps } from '@/utils/tree' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const areaList = ref([]) // 鍦板尯鍒楄〃 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const formData = ref({ - id: undefined, - name: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - industryId: undefined, - level: undefined, - source: undefined, - remark: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '瀹㈡埛鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await CustomerApi.getCustomer(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱鍦板尯鍒楄〃 - areaList.value = await AreaApi.getAreaTree() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as CustomerApi.CustomerVO - if (formType.value === 'create') { - await CustomerApi.createCustomer(data) - message.success(t('common.createSuccess')) - } else { - await CustomerApi.updateCustomer(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - contactNextTime: undefined, - ownerUserId: 0, - mobile: undefined, - telephone: undefined, - qq: undefined, - wechat: undefined, - email: undefined, - areaId: undefined, - detailAddress: undefined, - industryId: undefined, - level: undefined, - source: undefined, - remark: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/customer/CustomerImportForm.vue b/src/views/crm/customer/CustomerImportForm.vue deleted file mode 100644 index 17721a1..0000000 --- a/src/views/crm/customer/CustomerImportForm.vue +++ /dev/null @@ -1,158 +0,0 @@ -<!-- 瀹㈡埛瀵煎叆绐楀彛 --> -<template> - <Dialog v-model="dialogVisible" title="瀹㈡埛瀵煎叆" width="400"> - <div class="flex items-center my-10px"> - <span class="mr-10px">璐熻矗浜�</span> - <el-select v-model="ownerUserId" class="!w-240px" clearable> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </div> - <el-upload - ref="uploadRef" - v-model:file-list="fileList" - :auto-upload="false" - :disabled="formLoading" - :limit="1" - :on-exceed="handleExceed" - accept=".xlsx, .xls" - action="none" - drag - > - <Icon icon="ep:upload" /> - <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div> - <template #tip> - <div class="el-upload__tip text-center"> - <div class="el-upload__tip"> - <el-checkbox v-model="updateSupport" /> - 鏄惁鏇存柊宸茬粡瀛樺湪鐨勫鎴锋暟鎹紙鈥滃鎴峰悕绉扳�濋噸澶嶏級 - </div> - <span>浠呭厑璁稿鍏� xls銆亁lsx 鏍煎紡鏂囦欢銆�</span> - <el-link - :underline="false" - style="font-size: 12px; vertical-align: baseline" - type="primary" - @click="importTemplate" - > - 涓嬭浇妯℃澘 - </el-link> - </div> - </template> - </el-upload> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import download from '@/utils/download' -import type { UploadUserFile } from 'element-plus' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' - -defineOptions({ name: 'SystemUserImportForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const uploadRef = ref() -const fileList = ref<UploadUserFile[]>([]) // 鏂囦欢鍒楄〃 -const updateSupport = ref(false) // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勫鎴锋暟鎹� -const ownerUserId = ref<undefined | number>() // 璐熻矗浜虹紪鍙� -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - await resetForm() - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - ownerUserId.value = useUserStore().getUser.id -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const submitForm = async () => { - if (fileList.value.length == 0) { - message.error('璇蜂笂浼犳枃浠�') - return - } - - formLoading.value = true - try { - const formData = new FormData() - formData.append('updateSupport', String(updateSupport.value)) - formData.append('file', fileList.value[0].raw as Blob) - formData.append('ownerUserId', String(ownerUserId.value)) - const res = await CustomerApi.handleImport(formData) - submitFormSuccess(res) - } catch { - submitFormError() - } finally { - formLoading.value = false - } -} - -/** 鏂囦欢涓婁紶鎴愬姛 */ -const emits = defineEmits(['success']) -const submitFormSuccess = (response: any) => { - if (response.code !== 0) { - message.error(response.msg) - formLoading.value = false - return - } - // 鎷兼帴鎻愮ず璇� - const data = response.data - let text = '涓婁紶鎴愬姛鏁伴噺锛�' + data.createCustomerNames.length + ';' - for (let customerName of data.createCustomerNames) { - text += '< ' + customerName + ' >' - } - text += '鏇存柊鎴愬姛鏁伴噺锛�' + data.updateCustomerNames.length + ';' - for (const customerName of data.updateCustomerNames) { - text += '< ' + customerName + ' >' - } - text += '鏇存柊澶辫触鏁伴噺锛�' + Object.keys(data.failureCustomerNames).length + ';' - for (const customerName in data.failureCustomerNames) { - text += '< ' + customerName + ': ' + data.failureCustomerNames[customerName] + ' >' - } - message.alert(text) - formLoading.value = false - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emits('success') -} - -/** 涓婁紶閿欒鎻愮ず */ -const submitFormError = (): void => { - message.error('涓婁紶澶辫触锛岃鎮ㄩ噸鏂颁笂浼狅紒') - formLoading.value = false -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = async () => { - // 閲嶇疆涓婁紶鐘舵�佸拰鏂囦欢 - fileList.value = [] - updateSupport.value = false - ownerUserId.value = undefined - await nextTick() - uploadRef.value?.clearFiles() -} - -/** 鏂囦欢鏁拌秴鍑烘彁绀� */ -const handleExceed = (): void => { - message.error('鏈�澶氬彧鑳戒笂浼犱竴涓枃浠讹紒') -} - -/** 涓嬭浇妯℃澘鎿嶄綔 */ -const importTemplate = async () => { - const res = await CustomerApi.importCustomerTemplate() - download.excel(res, '瀹㈡埛瀵煎叆妯$増.xls') -} -</script> diff --git a/src/views/crm/customer/detail/CustomerDetailsHeader.vue b/src/views/crm/customer/detail/CustomerDetailsHeader.vue deleted file mode 100644 index 514ec61..0000000 --- a/src/views/crm/customer/detail/CustomerDetailsHeader.vue +++ /dev/null @@ -1,43 +0,0 @@ -<template> - <div v-loading="loading"> - <div class="flex items-start justify-between"> - <div> - <!-- 宸︿笂锛氬鎴峰熀鏈俊鎭� --> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ customer.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛绾у埆"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="customer.level" /> - </el-descriptions-item> - <el-descriptions-item label="鎴愪氦鐘舵��"> - {{ customer.dealStatus ? '宸叉垚浜�' : '鏈垚浜�' }} - </el-descriptions-item> - <el-descriptions-item label="璐熻矗浜�">{{ customer.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(customer.createTime) }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import * as CustomerApi from '@/api/crm/customer' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'CrmCustomerDetailsHeader' }) -defineProps<{ - customer: CustomerApi.CustomerVO // 瀹㈡埛淇℃伅 - loading: boolean // 鍔犺浇涓� -}>() -</script> diff --git a/src/views/crm/customer/detail/CustomerDetailsInfo.vue b/src/views/crm/customer/detail/CustomerDetailsInfo.vue deleted file mode 100644 index d9ea62a..0000000 --- a/src/views/crm/customer/detail/CustomerDetailsInfo.vue +++ /dev/null @@ -1,72 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames" class=""> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ customer.name }} - </el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鏉ユ簮"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="customer.source" /> - </el-descriptions-item> - <el-descriptions-item label="鎵嬫満">{{ customer.mobile }}</el-descriptions-item> - <el-descriptions-item label="鐢佃瘽">{{ customer.telephone }}</el-descriptions-item> - <el-descriptions-item label="閭">{{ customer.email }}</el-descriptions-item> - <el-descriptions-item label="鍦板潃"> - {{ customer.areaName }} {{ customer.detailAddress }} - </el-descriptions-item> - <el-descriptions-item label="QQ">{{ customer.qq }}</el-descriptions-item> - <el-descriptions-item label="寰俊">{{ customer.wechat }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛琛屼笟"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="customer.industryId" /> - </el-descriptions-item> - <el-descriptions-item label="瀹㈡埛绾у埆"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="customer.level" /> - </el-descriptions-item> - <el-descriptions-item label="涓嬫鑱旂郴鏃堕棿"> - {{ formatDate(customer.contactNextTime) }} - </el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ customer.remark }}</el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�">{{ customer.ownerUserName }}</el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涜褰�"> - {{ customer.contactLastContent }} - </el-descriptions-item> - <el-descriptions-item label="鏈�鍚庤窡杩涙椂闂�"> - {{ formatDate(customer.contactLastTime) }} - </el-descriptions-item> - <el-descriptions-item label=""> </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�">{{ customer.creatorName }}</el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(customer.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(customer.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'CrmCustomerDetailsInfo' }) -const { customer } = defineProps<{ - customer: CustomerApi.CustomerVO // 瀹㈡埛鏄庣粏 -}>() - -const activeNames = ref(['basicInfo', 'systemInfo']) // 灞曠ず鐨勬姌鍙犻潰鏉� -</script> -<style lang="scss" scoped></style> diff --git a/src/views/crm/customer/detail/index.vue b/src/views/crm/customer/detail/index.vue deleted file mode 100644 index 6818f69..0000000 --- a/src/views/crm/customer/detail/index.vue +++ /dev/null @@ -1,222 +0,0 @@ -<template> - <CustomerDetailsHeader :customer="customer" :loading="loading"> - <el-button - v-if="permissionListRef?.validateWrite" - v-hasPermi="['crm:customer:update']" - type="primary" - @click="openForm" - > - 缂栬緫 - </el-button> - <el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transfer"> - 杞Щ - </el-button> - <el-button v-if="permissionListRef?.validateWrite" @click="handleUpdateDealStatus"> - 鏇存敼鎴愪氦鐘舵�� - </el-button> - <el-button - v-if="customer.lockStatus && permissionListRef?.validateOwnerUser" - @click="handleUnlock" - > - 瑙i攣 - </el-button> - <el-button - v-if="!customer.lockStatus && permissionListRef?.validateOwnerUser" - @click="handleLock" - > - 閿佸畾 - </el-button> - <el-button v-if="!customer.ownerUserId" type="primary" @click="handleReceive"> 棰嗗彇</el-button> - <el-button v-if="!customer.ownerUserId" type="primary" @click="handleDistributeForm"> - 鍒嗛厤 - </el-button> - <el-button - v-if="customer.ownerUserId && permissionListRef?.validateOwnerUser" - @click="handlePutPool" - > - 鏀惧叆鍏捣 - </el-button> - </CustomerDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璺熻繘璁板綍"> - <FollowUpList :biz-id="customerId" :biz-type="BizTypeEnum.CRM_CUSTOMER" /> - </el-tab-pane> - <el-tab-pane label="鍩烘湰淇℃伅"> - <CustomerDetailsInfo :customer="customer" /> - </el-tab-pane> - <el-tab-pane label="鑱旂郴浜�" lazy> - <ContactList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="customer.id!" - :biz-type="BizTypeEnum.CRM_CUSTOMER" - :show-action="!permissionListRef?.isPool || false" - @quit-team="close" - /> - </el-tab-pane> - <el-tab-pane label="鍟嗘満" lazy> - <BusinessList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" /> - </el-tab-pane> - <el-tab-pane label="鍚堝悓" lazy> - <ContractList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" /> - </el-tab-pane> - <el-tab-pane label="鍥炴" lazy> - <ReceivablePlanList :customer-id="customer.id!" @create-receivable="createReceivable" /> - <ReceivableList ref="receivableListRef" :customer-id="customer.id!" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CustomerForm ref="formRef" @success="getCustomer" /> - <CustomerDistributeForm ref="distributeForm" @success="getCustomer" /> - <CrmTransferForm ref="transferFormRef" :biz-type="BizTypeEnum.CRM_CUSTOMER" @success="close" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as CustomerApi from '@/api/crm/customer' -import CustomerForm from '@/views/crm/customer/CustomerForm.vue' -import CustomerDetailsInfo from './CustomerDetailsInfo.vue' // 瀹㈡埛鏄庣粏 - 璇︾粏淇℃伅 -import CustomerDetailsHeader from './CustomerDetailsHeader.vue' // 瀹㈡埛鏄庣粏 - 澶撮儴 -import ContactList from '@/views/crm/contact/components/ContactList.vue' // 鑱旂郴浜哄垪琛� -import ContractList from '@/views/crm/contract/components/ContractList.vue' // 鍚堝悓鍒楄〃 -import BusinessList from '@/views/crm/business/components/BusinessList.vue' // 鍟嗘満鍒楄〃 -import ReceivableList from '@/views/crm/receivable/components/ReceivableList.vue' // 鍥炴鍒楄〃 -import ReceivablePlanList from '@/views/crm/receivable/plan/components/ReceivablePlanList.vue' // 鍥炴璁″垝鍒楄〃 -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue' -import FollowUpList from '@/views/crm/followup/index.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import type { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' -import CustomerDistributeForm from '@/views/crm/customer/pool/CustomerDistributeForm.vue' - -defineOptions({ name: 'CrmCustomerDetail' }) - -const customerId = ref(0) // 瀹㈡埛缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const message = useMessage() // 娑堟伅寮圭獥 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { push, currentRoute } = useRouter() // 璺敱 - -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const customer = ref<CustomerApi.CustomerVO>({} as CustomerApi.CustomerVO) // 瀹㈡埛璇︽儏 -const getCustomer = async () => { - loading.value = true - try { - customer.value = await CustomerApi.getCustomer(customerId.value) - await getOperateLog() - } finally { - loading.value = false - } -} - -/** 缂栬緫瀹㈡埛 */ -const formRef = ref<InstanceType<typeof CustomerForm>>() // 瀹㈡埛琛ㄥ崟 Ref -const openForm = () => { - formRef.value?.open('update', customerId.value) -} - -/** 鏇存柊鎴愪氦鐘舵�佹搷浣� */ -const handleUpdateDealStatus = async () => { - const dealStatus = !customer.value.dealStatus - try { - // 鏇存柊鐘舵�佺殑浜屾纭 - await message.confirm(`纭畾鏇存柊鎴愪氦鐘舵�佷负銆�${dealStatus ? '宸叉垚浜�' : '鏈垚浜�'}銆戝悧锛焋) - // 鍙戣捣鏇存柊 - await CustomerApi.updateCustomerDealStatus(customerId.value, dealStatus) - message.success(`鏇存柊鎴愪氦鐘舵�佹垚鍔焋) - // 鍒锋柊鏁版嵁 - await getCustomer() - } catch {} -} - -/** 瀹㈡埛杞Щ */ -const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // 瀹㈡埛杞Щ琛ㄥ崟 ref -const transfer = () => { - transferFormRef.value?.open(customerId.value) -} - -/** 閿佸畾瀹㈡埛 */ -const handleLock = async () => { - await message.confirm(`纭畾閿佸畾瀹㈡埛銆�${customer.value.name}銆� 鍚楋紵`) - await CustomerApi.lockCustomer(unref(customerId.value), true) - message.success(`閿佸畾瀹㈡埛銆�${customer.value.name}銆戞垚鍔焋) - await getCustomer() -} - -/** 瑙i攣瀹㈡埛 */ -const handleUnlock = async () => { - await message.confirm(`纭畾瑙i攣瀹㈡埛銆�${customer.value.name}銆� 鍚楋紵`) - await CustomerApi.lockCustomer(unref(customerId.value), false) - message.success(`瑙i攣瀹㈡埛銆�${customer.value.name}銆戞垚鍔焋) - await getCustomer() -} - -/** 棰嗗彇瀹㈡埛 */ -const handleReceive = async () => { - await message.confirm(`纭畾棰嗗彇瀹㈡埛銆�${customer.value.name}銆� 鍚楋紵`) - await CustomerApi.receiveCustomer([unref(customerId.value)]) - message.success(`棰嗗彇瀹㈡埛銆�${customer.value.name}銆戞垚鍔焋) - await getCustomer() -} - -/** 鍒嗛厤瀹㈡埛 */ -const distributeForm = ref<InstanceType<typeof CustomerDistributeForm>>() // 鍒嗛厤瀹㈡埛琛ㄥ崟 Ref -const handleDistributeForm = async () => { - distributeForm.value?.open(customerId.value) -} - -/** 瀹㈡埛鏀惧叆鍏捣 */ -const handlePutPool = async () => { - await message.confirm(`纭畾灏嗗鎴枫��${customer.value.name}銆戞斁鍏ュ叕娴峰悧锛焋) - await CustomerApi.putCustomerPool(unref(customerId.value)) - message.success(`瀹㈡埛銆�${customer.value.name}銆戞斁鍏ュ叕娴锋垚鍔焋) - // 鍔犺浇 - close() -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async () => { - if (!customerId.value) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_CUSTOMER, - bizId: customerId.value - }) - logList.value = data.list -} - -/** 浠庡洖娆捐鍒掑垱寤哄洖娆� */ -const receivableListRef = ref<InstanceType<typeof ReceivableList>>() // 鍥炴鍒楄〃 Ref -const createReceivable = (planData: any) => { - receivableListRef.value?.createReceivable(planData) -} - -const close = () => { - delView(unref(currentRoute)) - push({ name: 'CrmCustomer' }) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(() => { - if (!params.id) { - message.warning('鍙傛暟閿欒锛屽鎴蜂笉鑳戒负绌猴紒') - close() - return - } - customerId.value = params.id as unknown as number - getCustomer() -}) -</script> diff --git a/src/views/crm/customer/index.vue b/src/views/crm/customer/index.vue deleted file mode 100644 index 86bddc0..0000000 --- a/src/views/crm/customer/index.vue +++ /dev/null @@ -1,343 +0,0 @@ -<template> - <doc-alert title="銆愬鎴枫�戝鎴风鐞嗐�佸叕娴峰鎴�" url="https://doc.iocoder.cn/crm/customer/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="瀹㈡埛鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ鎴峰悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵嬫満" prop="mobile"> - <el-input - v-model="queryParams.mobile" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ墜鏈�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵�灞炶涓�" prop="industryId"> - <el-select - v-model="queryParams.industryId" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨鎵�灞炶涓�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="瀹㈡埛绾у埆" prop="level"> - <el-select - v-model="queryParams.level" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨瀹㈡埛绾у埆" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="瀹㈡埛鏉ユ簮" prop="source"> - <el-select - v-model="queryParams.source" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨瀹㈡埛鏉ユ簮" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['crm:customer:create']" type="primary" @click="openForm('create')"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button v-hasPermi="['crm:customer:import']" plain type="warning" @click="handleImport"> - <Icon icon="ep:upload" /> - 瀵煎叆 - </el-button> - <el-button - v-hasPermi="['crm:customer:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎵嬫満" prop="mobile" width="120" /> - <el-table-column align="center" label="鐢佃瘽" prop="telephone" width="130" /> - <el-table-column align="center" label="閭" prop="email" width="180" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column align="center" label="閿佸畾鐘舵��" prop="lockStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎴愪氦鐘舵��" prop="dealStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column align="center" label="鍦板潃" prop="detailAddress" width="180" /> - <el-table-column align="center" label="璺濈杩涘叆鍏捣澶╂暟" prop="poolDay" width="140"> - <template #default="scope"> {{ scope.row.poolDay }} 澶�</template> - </el-table-column> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="150"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:customer:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:customer:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CustomerForm ref="formRef" @success="getList" /> - <CustomerImportForm ref="importFormRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as CustomerApi from '@/api/crm/customer' -import CustomerForm from './CustomerForm.vue' -import CustomerImportForm from './CustomerImportForm.vue' -import { TabsPaneContext } from 'element-plus' - -defineOptions({ name: 'CrmCustomer' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - name: '', - mobile: '', - industryId: undefined, - level: undefined, - source: undefined, - pool: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName as string - handleQuery() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getCustomerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { currentRoute, push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await CustomerApi.deleteCustomer(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎叆鎸夐挳鎿嶄綔 */ -const importFormRef = ref<InstanceType<typeof CustomerImportForm>>() -const handleImport = () => { - importFormRef.value?.open() -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await CustomerApi.exportCustomer(queryParams) - download.excel(data, '瀹㈡埛.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鐩戝惉璺敱鍙樺寲鏇存柊鍒楄〃 */ -watch( - () => currentRoute.value, - () => { - getList() - } -) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/customer/limitConfig/CustomerLimitConfigForm.vue b/src/views/crm/customer/limitConfig/CustomerLimitConfigForm.vue deleted file mode 100644 index c7338a4..0000000 --- a/src/views/crm/customer/limitConfig/CustomerLimitConfigForm.vue +++ /dev/null @@ -1,150 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="200px" - v-loading="formLoading" - > - <el-form-item label="瑙勫垯閫傜敤浜虹兢" prop="userIds"> - <el-select multiple filterable v-model="formData.userIds"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="瑙勫垯閫傜敤閮ㄩ棬" prop="deptIds"> - <el-tree-select - v-model="formData.deptIds" - :data="deptTree" - :props="defaultProps" - multiple - filterable - check-strictly - node-key="id" - placeholder="璇烽�夋嫨瑙勫垯閫傜敤閮ㄩ棬" - /> - </el-form-item> - <el-form-item - :label=" - formData.type === LimitConfType.CUSTOMER_QUANTITY_LIMIT - ? '鎷ユ湁瀹㈡埛鏁颁笂闄�' - : '閿佸畾瀹㈡埛鏁颁笂闄�' - " - prop="maxCount" - > - <el-input-number v-model="formData.maxCount" placeholder="璇疯緭鍏ユ暟閲忎笂闄�" /> - </el-form-item> - <el-form-item - label="鎴愪氦瀹㈡埛鏄惁鍗犵敤鎷ユ湁瀹㈡埛鏁�" - v-if="formData.type === LimitConfType.CUSTOMER_QUANTITY_LIMIT" - prop="dealCountEnabled" - > - <el-switch v-model="formData.dealCountEnabled" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as CustomerLimitConfigApi from '@/api/crm/customer/limitConfig' -import * as DeptApi from '@/api/system/dept' -import { defaultProps, handleTree } from '@/utils/tree' -import * as UserApi from '@/api/system/user' -import { cloneDeep } from 'lodash-es' -import { LimitConfType } from '@/api/crm/customer/limitConfig' -import { aw } from '../../../../../dist-prod/assets/index-9eac537b' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - type: LimitConfType.CUSTOMER_LOCK_LIMIT, // 缁欎釜榛樿鍊硷紝閬垮厤 IDE 鎶ラ敊 - userIds: undefined, - deptIds: undefined, - maxCount: undefined, - dealCountEnabled: false -}) -const formRules = reactive({ - type: [{ required: true, message: '瑙勫垯绫诲瀷涓嶈兘涓虹┖', trigger: 'change' }], - maxCount: [{ required: true, message: '鏁伴噺涓婇檺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const deptTree = ref() // 閮ㄩ棬鏍戝舰缁撴瀯 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, limitConfType: LimitConfType, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await CustomerLimitConfigApi.getCustomerLimitConfig(id) - } finally { - formLoading.value = false - } - } else { - formData.value.type = limitConfType - } - // 鑾峰緱閮ㄩ棬鏍� - deptTree.value = handleTree(await DeptApi.getSimpleDeptList()) - // 鑾峰緱鐢ㄦ埛 - userOptions.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as CustomerLimitConfigApi.CustomerLimitConfigVO - if (formType.value === 'create') { - await CustomerLimitConfigApi.createCustomerLimitConfig(data) - message.success(t('common.createSuccess')) - } else { - await CustomerLimitConfigApi.updateCustomerLimitConfig(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - type: LimitConfType.CUSTOMER_LOCK_LIMIT, - userIds: undefined, - deptIds: undefined, - maxCount: undefined, - dealCountEnabled: false - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/customer/limitConfig/CustomerLimitConfigList.vue b/src/views/crm/customer/limitConfig/CustomerLimitConfigList.vue deleted file mode 100644 index f5c488c..0000000 --- a/src/views/crm/customer/limitConfig/CustomerLimitConfigList.vue +++ /dev/null @@ -1,150 +0,0 @@ -<template> - <el-button plain @click="handleQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 鍒锋柊 </el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['crm:customer-limit-config:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - class="mt-4" - > - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column - label="瑙勫垯閫傜敤浜虹兢" - align="center" - :formatter="(row) => row.users?.map((user: any) => user.nickname).join('锛�')" - /> - <el-table-column - label="瑙勫垯閫傜敤閮ㄩ棬" - align="center" - :formatter="(row) => row.depts?.map((dept: any) => dept.name).join('锛�')" - /> - <el-table-column - :label=" - confType === LimitConfType.CUSTOMER_QUANTITY_LIMIT ? '鎷ユ湁瀹㈡埛鏁颁笂闄�' : '閿佸畾瀹㈡埛鏁颁笂闄�' - " - align="center" - prop="maxCount" - /> - <el-table-column - v-if="confType === LimitConfType.CUSTOMER_QUANTITY_LIMIT" - label="鎴愪氦瀹㈡埛鏄惁鍗犵敤鎷ユ湁瀹㈡埛鏁�" - align="center" - prop="dealCountEnabled" - min-width="100" - > - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealCountEnabled" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" min-width="110" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['crm:customer-limit-config:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['crm:customer-limit-config:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CustomerLimitConfigForm ref="formRef" @success="getList" /> -</template> -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as CustomerLimitConfigApi from '@/api/crm/customer/limitConfig' -import CustomerLimitConfigForm from './CustomerLimitConfigForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { LimitConfType } from '@/api/crm/customer/limitConfig' - -defineOptions({ name: 'CustomerLimitConfigList' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const { confType } = defineProps<{ confType: LimitConfType }>() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - type: confType -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerLimitConfigApi.getCustomerLimitConfigPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, confType, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await CustomerLimitConfigApi.deleteCustomerLimitConfig(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/customer/limitConfig/index.vue b/src/views/crm/customer/limitConfig/index.vue deleted file mode 100644 index 01f3ef6..0000000 --- a/src/views/crm/customer/limitConfig/index.vue +++ /dev/null @@ -1,22 +0,0 @@ -<template> - <doc-alert title="銆愬鎴枫�戝鎴风鐞嗐�佸叕娴峰鎴�" url="https://doc.iocoder.cn/crm/customer/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs> - <el-tab-pane label="鎷ユ湁瀹㈡埛鏁伴檺鍒�"> - <CustomerLimitConfigList :confType="LimitConfType.CUSTOMER_QUANTITY_LIMIT" /> - </el-tab-pane> - <el-tab-pane label="閿佸畾瀹㈡埛鏁伴檺鍒�"> - <CustomerLimitConfigList :confType="LimitConfType.CUSTOMER_LOCK_LIMIT" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> -</template> -<script setup lang="ts"> -import CustomerLimitConfigList from './CustomerLimitConfigList.vue' -import { LimitConfType } from '@/api/crm/customer/limitConfig' - -defineOptions({ name: 'CrmCustomerLimitConfig' }) -</script> diff --git a/src/views/crm/customer/pool/CustomerDistributeForm.vue b/src/views/crm/customer/pool/CustomerDistributeForm.vue deleted file mode 100644 index 5fd80a1..0000000 --- a/src/views/crm/customer/pool/CustomerDistributeForm.vue +++ /dev/null @@ -1,85 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍒嗛厤瀹㈡埛"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select v-model="formData.ownerUserId" class="w-1/1"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as CustomerApi from '@/api/crm/customer' -import * as UserApi from '@/api/system/user' -import { distributeCustomer } from '@/api/crm/customer' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const formData = ref({ - id: undefined, - ownerUserId: undefined -}) -const formRules = reactive({ - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - resetForm() - formData.value.id = id - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await CustomerApi.distributeCustomer([formData.value.id], formData.value.ownerUserId) - message.success('鍒嗛厤瀹㈡埛鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - ownerUserId: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/customer/pool/index.vue b/src/views/crm/customer/pool/index.vue deleted file mode 100644 index eab90e0..0000000 --- a/src/views/crm/customer/pool/index.vue +++ /dev/null @@ -1,270 +0,0 @@ -<template> - <doc-alert title="銆愬鎴枫�戝鎴风鐞嗐�佸叕娴峰鎴�" url="https://doc.iocoder.cn/crm/customer/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="瀹㈡埛鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ鎴峰悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵嬫満" prop="mobile"> - <el-input - v-model="queryParams.mobile" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ墜鏈�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵�灞炶涓�" prop="industryId"> - <el-select - v-model="queryParams.industryId" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨鎵�灞炶涓�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="瀹㈡埛绾у埆" prop="level"> - <el-select - v-model="queryParams.level" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨瀹㈡埛绾у埆" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="瀹㈡埛鏉ユ簮" prop="source"> - <el-select - v-model="queryParams.source" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨瀹㈡埛鏉ユ簮" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery(undefined)"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['crm:customer:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" fixed="left" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column label="鎵嬫満" align="center" prop="mobile" width="120" /> - <el-table-column label="鐢佃瘽" align="center" prop="telephone" width="130" /> - <el-table-column label="閭" align="center" prop="email" width="180" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="135"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column align="center" label="鎴愪氦鐘舵��" prop="dealStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column align="center" label="鏈�鍚庤窡杩涜褰�" prop="contactLastContent" width="200" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as CustomerApi from '@/api/crm/customer' - -defineOptions({ name: 'CrmCustomerPool' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - name: '', - mobile: '', - industryId: undefined, - level: undefined, - source: undefined, - sceneType: undefined, - pool: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getCustomerPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - queryParams.value = { - pageNo: 1, - pageSize: 10, - name: '', - mobile: '', - industryId: undefined, - level: undefined, - source: undefined, - sceneType: undefined, - pool: true - } - handleQuery() -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { currentRoute, push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await CustomerApi.exportCustomer(queryParams.value) - download.excel(data, '瀹㈡埛鍏捣.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鐩戝惉璺敱鍙樺寲鏇存柊鍒楄〃 */ -watch( - () => currentRoute.value, - () => { - getList() - } -) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/customer/poolConfig/index.vue b/src/views/crm/customer/poolConfig/index.vue deleted file mode 100644 index 2880887..0000000 --- a/src/views/crm/customer/poolConfig/index.vue +++ /dev/null @@ -1,136 +0,0 @@ -<template> - <doc-alert title="銆愬鎴枫�戝鎴风鐞嗐�佸叕娴峰鎴�" url="https://doc.iocoder.cn/crm/customer/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="160px" - v-loading="formLoading" - > - <el-card shadow="never"> - <!-- 鎿嶄綔 --> - <template #header> - <div class="flex items-center justify-between"> - <CardTitle title="瀹㈡埛鍏捣瑙勫垯璁剧疆" /> - <el-button - type="primary" - @click="onSubmit" - v-hasPermi="['crm:customer-pool-config:update']" - > - 淇濆瓨 - </el-button> - </div> - </template> - <!-- 琛ㄥ崟 --> - <el-form-item label="瀹㈡埛鍏捣瑙勫垯璁剧疆" prop="enabled"> - <el-radio-group v-model="formData.enabled" @change="changeEnable" class="ml-4"> - <el-radio :label="false" size="large">涓嶅惎鐢�</el-radio> - <el-radio :label="true" size="large">鍚敤</el-radio> - </el-radio-group> - </el-form-item> - <div v-if="formData.enabled"> - <el-form-item> - <el-input-number class="mr-2" v-model="formData.contactExpireDays" /> - 澶╀笉璺熻繘鎴� - <el-input-number class="mx-2" v-model="formData.dealExpireDays" /> - 澶╂湭鎴愪氦 - </el-form-item> - <el-form-item label="鎻愬墠鎻愰啋璁剧疆" prop="notifyEnabled"> - <el-radio-group - v-model="formData.notifyEnabled" - @change="changeNotifyEnable" - class="ml-4" - > - <el-radio :label="false" size="large">涓嶆彁閱�</el-radio> - <el-radio :label="true" size="large">鎻愰啋</el-radio> - </el-radio-group> - </el-form-item> - <div v-if="formData.notifyEnabled"> - <el-form-item> - 鎻愬墠 <el-input-number class="mx-2" v-model="formData.notifyDays" /> 澶╂彁閱� - </el-form-item> - </div> - </div> - </el-card> - </el-form> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as CustomerPoolConfigApi from '@/api/crm/customer/poolConfig' -import { CardTitle } from '@/components/Card' - -defineOptions({ name: 'CrmCustomerPoolConfig' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const formLoading = ref(false) -const formData = ref({ - enabled: false, - contactExpireDays: undefined, - dealExpireDays: undefined, - notifyEnabled: false, - notifyDays: undefined -}) -const formRules = reactive({ - enabled: [{ required: true, message: '鏄惁鍚敤瀹㈡埛鍏捣涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鑾峰彇閰嶇疆 */ -const getConfig = async () => { - try { - formLoading.value = true - const data = await CustomerPoolConfigApi.getCustomerPoolConfig() - if (data === null) { - return - } - formData.value = data - } finally { - formLoading.value = false - } -} - -/** 鎻愪氦閰嶇疆 */ -const onSubmit = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as CustomerPoolConfigApi.CustomerPoolConfigVO - await CustomerPoolConfigApi.saveCustomerPoolConfig(data) - message.success(t('common.updateSuccess')) - await getConfig() - formLoading.value = false - } finally { - formLoading.value = false - } -} - -/** 鏇存敼瀹㈡埛鍏捣瑙勫垯璁剧疆 */ -const changeEnable = () => { - if (!formData.value.enabled) { - formData.value.contactExpireDays = undefined - formData.value.dealExpireDays = undefined - formData.value.notifyEnabled = false - formData.value.notifyDays = undefined - } -} - -/** 鏇存敼鎻愬墠鎻愰啋璁剧疆 */ -const changeNotifyEnable = () => { - if (!formData.value.notifyEnabled) { - formData.value.notifyDays = undefined - } -} - -onMounted(() => { - getConfig() -}) -</script> diff --git a/src/views/crm/followup/FollowUpRecordForm.vue b/src/views/crm/followup/FollowUpRecordForm.vue deleted file mode 100644 index eb626f0..0000000 --- a/src/views/crm/followup/FollowUpRecordForm.vue +++ /dev/null @@ -1,188 +0,0 @@ -<!-- 璺熻繘璁板綍鐨勬坊鍔犺〃鍗曞脊绐� --> -<template> - <Dialog v-model="dialogVisible" title="娣诲姞璺熻繘璁板綍" width="50%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="120px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="璺熻繘绫诲瀷" prop="type"> - <el-select v-model="formData.type" placeholder="璇烽�夋嫨璺熻繘绫诲瀷"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_FOLLOW_UP_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="涓嬫鑱旂郴鏃堕棿" prop="nextTime"> - <el-date-picker - v-model="formData.nextTime" - placeholder="閫夋嫨涓嬫鑱旂郴鏃堕棿" - type="date" - value-format="x" - /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="璺熻繘鍐呭" prop="content"> - <el-input v-model="formData.content" :rows="3" type="textarea" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍥剧墖" prop="picUrls"> - <UploadImgs v-model="formData.picUrls" class="min-w-80px" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="闄勪欢" prop="fileUrls"> - <UploadFile v-model="formData.fileUrls" class="min-w-80px" /> - </el-form-item> - </el-col> - <el-col :span="24" v-if="formData.bizType == BizTypeEnum.CRM_CUSTOMER"> - <el-form-item label="鍏宠仈鑱旂郴浜�" prop="contactIds"> - <el-button @click="handleOpenContact"> - <Icon class="mr-5px" icon="ep:plus" /> - 娣诲姞鑱旂郴浜� - </el-button> - <FollowUpRecordContactForm :contacts="formData.contacts" /> - </el-form-item> - </el-col> - <el-col :span="24" v-if="formData.bizType == BizTypeEnum.CRM_CUSTOMER"> - <el-form-item label="鍏宠仈鍟嗘満" prop="businessIds"> - <el-button @click="handleOpenBusiness"> - <Icon class="mr-5px" icon="ep:plus" /> - 娣诲姞鍟嗘満 - </el-button> - <FollowUpRecordBusinessForm :businesses="formData.businesses" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - - <!-- 寮圭獥 --> - <ContactListModal - ref="contactTableSelectRef" - :customer-id="formData.bizId" - @success="handleAddContact" - /> - <BusinessListModal - ref="businessTableSelectRef" - :customer-id="formData.bizId" - @success="handleAddBusiness" - /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { FollowUpRecordApi, FollowUpRecordVO } from '@/api/crm/followup' -import { BizTypeEnum } from '@/api/crm/permission' -import FollowUpRecordBusinessForm from './components/FollowUpRecordBusinessForm.vue' -import FollowUpRecordContactForm from './components/FollowUpRecordContactForm.vue' -import BusinessListModal from '@/views/crm/business/components/BusinessListModal.vue' -import * as BusinessApi from '@/api/crm/business' -import ContactListModal from '@/views/crm/contact/components/ContactListModal.vue' -import * as ContactApi from '@/api/crm/contact' - -defineOptions({ name: 'FollowUpRecordForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - bizType: undefined, - bizId: undefined, - businesses: [], - contacts: [] -}) -const formRules = reactive({ - type: [{ required: true, message: '璺熻繘绫诲瀷涓嶈兘涓虹┖', trigger: 'change' }], - content: [{ required: true, message: '璺熻繘鍐呭涓嶈兘涓虹┖', trigger: 'blur' }], - nextTime: [{ required: true, message: '涓嬫鑱旂郴鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (bizType: number, bizId: number) => { - dialogVisible.value = true - resetForm() - formData.value.bizType = bizType - formData.value.bizId = bizId -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { - ...formData.value, - contactIds: formData.value.contacts.map((item) => item.id), - businessIds: formData.value.businesses.map((item) => item.id) - } as unknown as FollowUpRecordVO - await FollowUpRecordApi.createFollowUpRecord(data) - message.success(t('common.createSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 鍏宠仈鑱旂郴浜� */ -const contactTableSelectRef = ref<InstanceType<typeof ContactListModal>>() -const handleOpenContact = () => { - contactTableSelectRef.value?.open() -} -const handleAddContact = (contactId: [], newContacts: ContactApi.ContactVO[]) => { - newContacts.forEach((contact) => { - if (!formData.value.contacts.some((item) => item.id === contact.id)) { - formData.value.contacts.push(contact) - } - }) -} - -/** 鍏宠仈鍟嗘満 */ -const businessTableSelectRef = ref<InstanceType<typeof BusinessListModal>>() -const handleOpenBusiness = () => { - businessTableSelectRef.value?.open() -} -const handleAddBusiness = (businessId: [], newBusinesses: BusinessApi.BusinessVO[]) => { - newBusinesses.forEach((business) => { - if (!formData.value.businesses.some((item) => item.id === business.id)) { - formData.value.businesses.push(business) - } - }) -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formRef.value?.resetFields() - formData.value = { - bizId: undefined, - bizType: undefined, - businesses: [], - contacts: [] - } -} -</script> diff --git a/src/views/crm/followup/components/FollowUpRecordBusinessForm.vue b/src/views/crm/followup/components/FollowUpRecordBusinessForm.vue deleted file mode 100644 index 620b5fb..0000000 --- a/src/views/crm/followup/components/FollowUpRecordBusinessForm.vue +++ /dev/null @@ -1,42 +0,0 @@ -<template> - <el-table :data="formData" :show-overflow-tooltip="true" :stripe="true" height="120"> - <el-table-column label="鍟嗘満鍚嶇О" fixed="left" align="center" prop="name" /> - <el-table-column - label="鍟嗘満閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="瀹㈡埛鍚嶇О" align="center" prop="customerName" /> - <el-table-column label="鍟嗘満缁�" align="center" prop="statusTypeName" /> - <el-table-column label="鍟嗘満闃舵" align="center" prop="statusName" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="80"> - <template #default="{ $index }"> - <el-button link type="danger" @click="handleDelete($index)"> 绉婚櫎</el-button> - </template> - </el-table-column> - </el-table> -</template> - -<script lang="ts" setup> -import { erpPriceTableColumnFormatter } from '@/utils' - -const props = defineProps<{ - businesses: undefined -}>() -const formData = ref([]) - -/** 鍒濆鍖栧晢鏈哄垪琛� */ -watch( - () => props.businesses, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} -</script> diff --git a/src/views/crm/followup/components/FollowUpRecordContactForm.vue b/src/views/crm/followup/components/FollowUpRecordContactForm.vue deleted file mode 100644 index b3b5d3a..0000000 --- a/src/views/crm/followup/components/FollowUpRecordContactForm.vue +++ /dev/null @@ -1,47 +0,0 @@ -<template> - <el-table :data="contacts" :show-overflow-tooltip="true" :stripe="true" height="150"> - <el-table-column label="濮撳悕" fixed="left" align="center" prop="name"> - <template #default="scope"> - <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column label="鎵嬫満鍙�" align="center" prop="mobile" /> - <el-table-column label="鑱屼綅" align="center" prop="post" /> - <el-table-column label="鐩村睘涓婄骇" align="center" prop="parentName" /> - <el-table-column label="鏄惁鍏抽敭鍐崇瓥浜�" align="center" prop="master" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="130"> - <template #default="scope"> - <el-button link type="danger" @click="handleDelete(scope.row.id)"> 绉婚櫎</el-button> - </template> - </el-table-column> - </el-table> -</template> - -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' - -const props = defineProps<{ - contacts: undefined -}>() -const formData = ref([]) - -/** 鍒濆鍖栬仈绯讳汉鍒楄〃 */ -watch( - () => props.contacts, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} -</script> diff --git a/src/views/crm/followup/index.vue b/src/views/crm/followup/index.vue deleted file mode 100644 index d0b2271..0000000 --- a/src/views/crm/followup/index.vue +++ /dev/null @@ -1,167 +0,0 @@ -<!-- 鏌愪釜璁板綍鐨勮窡杩涜褰曞垪琛紝鐩墠涓昏鐢ㄤ簬 CRM 瀹㈡埛銆佸晢鏈虹瓑璇︽儏鐣岄潰 --> -<template> - <!-- 鎿嶄綔鏍� --> - <el-row class="mb-10px" justify="end"> - <el-button @click="openForm"> - <Icon class="mr-5px" icon="ep:edit" /> - 鍐欒窡杩� - </el-button> - </el-row> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="璺熻繘浜�" prop="creatorName" /> - <el-table-column align="center" label="璺熻繘绫诲瀷" prop="type"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_FOLLOW_UP_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column align="center" label="璺熻繘鍐呭" prop="content" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="nextTime" - width="180px" - /> - <el-table-column - align="center" - label="鍏宠仈鑱旂郴浜�" - prop="contactIds" - v-if="bizType === BizTypeEnum.CRM_CUSTOMER" - > - <template #default="scope"> - <el-link - v-for="contact in scope.row.contacts" - :key="`key-${contact.id}`" - :underline="false" - type="primary" - @click="openContactDetail(contact.id)" - class="ml-5px" - > - {{ contact.name }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="鍏宠仈鍟嗘満" - prop="businessIds" - v-if="bizType === BizTypeEnum.CRM_CUSTOMER" - > - <template #default="scope"> - <el-link - v-for="business in scope.row.businesses" - :key="`key-${business.id}`" - :underline="false" - type="primary" - @click="openBusinessDetail(business.id)" - class="ml-5px" - > - {{ business.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button link type="danger" @click="handleDelete(scope.row.id)"> 鍒犻櫎 </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <FollowUpRecordForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import { DICT_TYPE } from '@/utils/dict' -import { FollowUpRecordApi, FollowUpRecordVO } from '@/api/crm/followup' -import FollowUpRecordForm from './FollowUpRecordForm.vue' -import { BizTypeEnum } from '@/api/crm/permission' - -/** 璺熻繘璁板綍鍒楄〃 */ -defineOptions({ name: 'FollowUpRecord' }) -const props = defineProps<{ - bizType: number - bizId: number -}>() -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<FollowUpRecordVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - bizType: 0, - bizId: 0 -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await FollowUpRecordApi.getFollowUpRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref<InstanceType<typeof FollowUpRecordForm>>() -const openForm = () => { - formRef.value?.open(props.bizType, props.bizId) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await FollowUpRecordApi.deleteFollowUpRecord(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎵撳紑鑱旂郴浜鸿鎯� */ -const { push } = useRouter() -const openContactDetail = (id: number) => { - push({ name: 'CrmContactDetail', params: { id } }) -} - -/** 鎵撳紑鍟嗘満璇︽儏 */ -const openBusinessDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -watch( - () => props.bizId, - () => { - queryParams.bizType = props.bizType - queryParams.bizId = props.bizId - getList() - } -) -</script> diff --git a/src/views/crm/permission/components/PermissionForm.vue b/src/views/crm/permission/components/PermissionForm.vue deleted file mode 100644 index 9cf8867..0000000 --- a/src/views/crm/permission/components/PermissionForm.vue +++ /dev/null @@ -1,137 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="30%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item v-if="formType === 'create'" label="閫夋嫨浜哄憳" prop="userId"> - <el-select v-model="formData.userId"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鏉冮檺绾у埆" prop="level"> - <el-radio-group v-model="formData.level"> - <template - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PERMISSION_LEVEL)" - :key="dict.value" - > - <el-radio v-if="dict.value != PermissionLevelEnum.OWNER" :label="dict.value"> - {{ dict.label }} - </el-radio> - </template> - </el-radio-group> - </el-form-item> - <el-form-item - v-if="formType === 'create' && formData.bizType === BizTypeEnum.CRM_CUSTOMER" - label="鍚屾椂娣诲姞鑷�" - > - <el-checkbox-group v-model="formData.toBizTypes"> - <el-checkbox :label="BizTypeEnum.CRM_CONTACT">鑱旂郴浜�</el-checkbox> - <el-checkbox :label="BizTypeEnum.CRM_BUSINESS">鍟嗘満</el-checkbox> - <el-checkbox :label="BizTypeEnum.CRM_CONTRACT">鍚堝悓</el-checkbox> - </el-checkbox-group> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as UserApi from '@/api/system/user' -import * as PermissionApi from '@/api/crm/permission' -import { BizTypeEnum, PermissionLevelEnum } from '@/api/crm/permission' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -defineOptions({ name: 'CrmPermissionForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const formData = ref<PermissionApi.PermissionVO>({} as PermissionApi.PermissionVO) -const formRules = reactive({ - userId: [{ required: true, message: '浜哄憳涓嶈兘涓虹┖', trigger: 'blur' }], - level: [{ required: true, message: '鏉冮檺绾у埆涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: 'create' | 'update', bizType: number, bizId: number, ids?: number[]) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) + '鍥㈤槦鎴愬憳' - formType.value = type - resetForm(bizType, bizId) - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (ids) { - formData.value.ids = ids - } -} -/** 鎵撳紑淇敼鏉冮檺寮圭獥 */ -const open0 = async ( - type: 'create' | 'update', - bizType: number, - bizId: number, - id: number, - level: number -) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) + '鍥㈤槦鎴愬憳' - formType.value = type - resetForm(bizType, bizId) - // 淇敼鏃讹紝璁剧疆鏁版嵁 - formData.value.level = level - formData.value.ids = [id] -} -defineExpose({ open, open0 }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value - if (formType.value === 'create') { - await PermissionApi.createPermission(unref(data)) - message.success(t('common.createSuccess')) - } else { - await PermissionApi.updatePermission(unref(data)) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = (bizType: number, bizId: number) => { - formRef.value?.resetFields() - formData.value = {} as PermissionApi.PermissionVO - formData.value = { ...formData.value, bizType, bizId } -} -onMounted(async () => { - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/crm/permission/components/PermissionList.vue b/src/views/crm/permission/components/PermissionList.vue deleted file mode 100644 index 39c7aab..0000000 --- a/src/views/crm/permission/components/PermissionList.vue +++ /dev/null @@ -1,206 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row v-if="showAction" justify="end"> - <el-button v-if="validateOwnerUser" type="primary" @click="openForm"> - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button v-if="validateOwnerUser" @click="handleUpdate"> - <Icon class="mr-5px" icon="ep:edit" /> - 缂栬緫 - </el-button> - <el-button v-if="validateOwnerUser" @click="handleDelete"> - <Icon class="mr-5px" icon="ep:delete" /> - 绉婚櫎 - </el-button> - <el-button v-if="!validateOwnerUser && list.length > 0" type="danger" @click="handleQuit"> - 閫�鍑哄洟闃� - </el-button> - </el-row> - <!-- 鍥㈤槦鎴愬憳灞曠ず --> - <el-table - ref="elTableRef" - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - class="mt-20px" - @selection-change="handleSelectionChange" - > - <el-table-column type="selection" width="55" /> - <el-table-column align="center" label="濮撳悕" prop="nickname" /> - <el-table-column align="center" label="閮ㄩ棬" prop="deptName" /> - <el-table-column align="center" label="宀椾綅" prop="postNames" /> - <el-table-column align="center" label="鏉冮檺绾у埆" prop="level"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.CRM_PERMISSION_LEVEL" :value="row.level" /> - </template> - </el-table-column> - <el-table-column :formatter="dateFormatter" align="center" label="鍔犲叆鏃堕棿" prop="createTime" /> - </el-table> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CrmPermissionForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import { ElTable } from 'element-plus' -import * as PermissionApi from '@/api/crm/permission' -import { useUserStoreWithOut } from '@/store/modules/user' -import CrmPermissionForm from './PermissionForm.vue' -import { DICT_TYPE } from '@/utils/dict' - -defineOptions({ name: 'CrmPermissionList' }) - -const message = useMessage() // 娑堟伅 - -const props = defineProps<{ - bizType: number // 妯″潡绫诲瀷 - bizId: number | undefined // 妯″潡鏁版嵁缂栧彿 - showAction: boolean //鏄惁灞曠ず鎿嶄綔鎸夐挳 -}>() -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<PermissionApi.PermissionVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const formData = ref({ - ownerUserId: 0 -}) -const userStore = useUserStoreWithOut() // 鐢ㄦ埛淇℃伅缂撳瓨 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PermissionApi.getPermissionList({ - bizType: props.bizType, - bizId: props.bizId - }) - list.value = data - const permission = list.value.find( - (item) => - item.userId === userStore.getUser.id && - item.level === PermissionApi.PermissionLevelEnum.OWNER - ) - if (permission) { - formData.value.ownerUserId = userStore.getUser.id - } - } finally { - loading.value = false - } -} -const multipleSelection = ref<PermissionApi.PermissionVO[]>([]) // 閫夋嫨鐨勫洟闃熸垚鍛� -const elTableRef = ref<InstanceType<typeof ElTable>>() -const handleSelectionChange = (val: PermissionApi.PermissionVO[]) => { - if (val.findIndex((item) => item.level === PermissionApi.PermissionLevelEnum.OWNER) !== -1) { - message.warning('涓嶈兘閫夋嫨璐熻矗浜猴紒') - elTableRef.value?.clearSelection() - return - } - multipleSelection.value = val -} - -/** 缂栬緫鍥㈤槦鎴愬憳 */ -const formRef = ref<InstanceType<typeof CrmPermissionForm>>() // 鏉冮檺琛ㄥ崟 Ref -const handleUpdate = () => { - if (multipleSelection.value?.length === 0) { - message.warning('璇峰厛閫夋嫨鍥㈤槦鎴愬憳鍚庢搷浣滐紒') - return - } - if (multipleSelection.value?.length > 1) { - message.warning('缂栬緫鍥㈤槦鎴愬憳鏃跺彧鑳介�夋嫨涓�涓紒') - return - } - formRef.value?.open0( - 'update', - props.bizType, - props.bizId!, - multipleSelection.value[0].id!, - multipleSelection.value[0].level - ) -} - -/** 绉婚櫎鍥㈤槦鎴愬憳 */ -const handleDelete = async () => { - if (multipleSelection.value?.length === 0) { - message.warning('璇峰厛閫夋嫨鍥㈤槦鎴愬憳鍚庢搷浣滐紒') - return - } - await message.delConfirm() - const ids = multipleSelection.value?.map((item) => item.id) as unknown as number[] - await PermissionApi.deletePermissionBatch(ids) - message.success('绉婚櫎鍥㈤槦鎴愬憳鎴愬姛锛�') - await getList() -} - -/** 娣诲姞鍥㈤槦鎴愬憳 */ -const openForm = () => { - formRef.value?.open('create', props.bizType, props.bizId!) -} - -// 鏍¢獙璐熻矗浜烘潈闄愬拰缂栬緫鏉冮檺 -const validateOwnerUser = ref(false) -const validateWrite = ref(false) -const isPool = ref(false) -watch( - list, - (newArr) => { - isPool.value = false - if (newArr?.length > 0) { - isPool.value = !list.value.some( - (item) => item.level === PermissionApi.PermissionLevelEnum.OWNER - ) - validateOwnerUser.value = false - validateWrite.value = false - const userId = userStore.getUser?.id - list.value - .filter((item) => item.userId === userId) - .forEach((item) => { - if (item.level === PermissionApi.PermissionLevelEnum.OWNER) { - validateOwnerUser.value = true - validateWrite.value = true - } else if (item.level === PermissionApi.PermissionLevelEnum.WRITE) { - validateWrite.value = true - } - }) - } else { - isPool.value = true - } - }, - { - immediate: true - } -) - -defineExpose({ openForm, validateOwnerUser, validateWrite, isPool }) -const emits = defineEmits<{ - (e: 'quitTeam'): void -}>() -/** 閫�鍑哄洟闃� */ -const handleQuit = async () => { - const permission = list.value.find( - (item) => - item.userId === userStore.getUser.id && item.level === PermissionApi.PermissionLevelEnum.OWNER - ) - if (permission) { - message.warning('璐熻矗浜轰笉鑳介��鍑哄洟闃燂紒') - return - } - const userPermission = list.value.find((item) => item.userId === userStore.getUser.id) - if (!userPermission) { - return - } - await PermissionApi.deleteSelfPermission(userPermission.id!) - message.success('閫�鍑哄洟闃熸垚鍛樻垚鍔燂紒') - emits('quitTeam') -} - -watch( - () => props.bizId, - (bizId) => { - if (!bizId) { - return - } - getList() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/permission/components/TransferForm.vue b/src/views/crm/permission/components/TransferForm.vue deleted file mode 100644 index 311071b..0000000 --- a/src/views/crm/permission/components/TransferForm.vue +++ /dev/null @@ -1,162 +0,0 @@ -<!-- 杞Щ鏁版嵁鐨勮〃鍗曞脊绐楋紝鐩墠涓昏鐢ㄤ簬 CRM 瀹㈡埛銆佸晢鏈虹瓑璇︽儏鐣岄潰 --> -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="30%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="150px" - > - <el-form-item label="閫夋嫨鏂拌礋璐d汉" prop="newOwnerUserId"> - <el-select v-model="formData.newOwnerUserId"> - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鑰佽礋璐d汉"> - <el-radio-group v-model="oldOwnerHandler" @change="handleOwnerChange"> - <el-radio :label="false" size="large">绉婚櫎</el-radio> - <el-radio :label="true" size="large">鍔犲叆鍥㈤槦</el-radio> - </el-radio-group> - </el-form-item> - <el-form-item v-if="oldOwnerHandler" label="鑰佽礋璐d汉鏉冮檺绾у埆" prop="oldOwnerPermissionLevel"> - <el-radio-group v-model="formData.oldOwnerPermissionLevel"> - <template - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PERMISSION_LEVEL)" - :key="dict.value" - > - <el-radio v-if="dict.value != PermissionLevelEnum.OWNER" :label="dict.value"> - {{ dict.label }} - </el-radio> - </template> - </el-radio-group> - </el-form-item> - <el-form-item v-if="bizType === BizTypeEnum.CRM_CUSTOMER" label="鍚屾椂杞Щ"> - <el-checkbox-group v-model="formData.toBizTypes"> - <el-checkbox :label="BizTypeEnum.CRM_CONTACT">鑱旂郴浜�</el-checkbox> - <el-checkbox :label="BizTypeEnum.CRM_BUSINESS">鍟嗘満</el-checkbox> - <el-checkbox :label="BizTypeEnum.CRM_CONTRACT">鍚堝悓</el-checkbox> - </el-checkbox-group> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as UserApi from '@/api/system/user' -import * as BusinessApi from '@/api/crm/business' -import * as ClueApi from '@/api/crm/clue' -import * as ContactApi from '@/api/crm/contact' -import * as CustomerApi from '@/api/crm/customer' -import * as ContractApi from '@/api/crm/contract' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { BizTypeEnum, PermissionLevelEnum, TransferReqVO } from '@/api/crm/permission' - -defineOptions({ name: 'CrmTransferForm' }) - -const props = defineProps<{ - bizType: number -}>() - -const message = useMessage() // 娑堟伅寮圭獥 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const oldOwnerHandler = ref(false) // 鑰佽礋璐d汉鐨勫鐞嗘柟寮� -const formData = ref<TransferReqVO>({} as TransferReqVO) -const formRules = reactive({ - newOwnerUserId: [{ required: true, message: '鏂拌礋璐d汉涓嶈兘涓虹┖', trigger: 'blur' }], - oldOwnerPermissionLevel: [ - { required: true, message: '鑰佽礋璐d汉鍔犲叆鍥㈤槦鍚庣殑鏉冮檺绾у埆涓嶈兘涓虹┖', trigger: 'blur' } - ] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (bizId: number) => { - dialogVisible.value = true - dialogTitle.value = getDialogTitle() - resetForm() - formData.value.id = bizId -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -// 鑰佽礋璐d汉璐熻矗鏂瑰紡 -const handleOwnerChange = (val: boolean) => { - if (!val) { - // 绉婚櫎鐨勮瘽鎻愪氦涓嶅甫 oldOwnerPermissionLevel 鍙傛暟 - formData.value.oldOwnerPermissionLevel = undefined - } -} -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value - await transfer(unref(data)) - message.success(dialogTitle.value + '鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} -const transfer = async (data: TransferReqVO) => { - switch (props.bizType) { - case BizTypeEnum.CRM_CLUE: - return await ClueApi.transferClue(data) - case BizTypeEnum.CRM_CUSTOMER: - return await CustomerApi.transferCustomer(data) - case BizTypeEnum.CRM_CONTACT: - return await ContactApi.transferContact(data) - case BizTypeEnum.CRM_BUSINESS: - return await BusinessApi.transferBusiness(data) - case BizTypeEnum.CRM_CONTRACT: - return await ContractApi.transferContract(data) - default: - message.error('銆愯浆绉诲け璐ャ�戞病鏈夎浆绉绘帴鍙�') - throw new Error('銆愯浆绉诲け璐ャ�戞病鏈夎浆绉绘帴鍙�') - } -} -const getDialogTitle = () => { - switch (props.bizType) { - case BizTypeEnum.CRM_CLUE: - return '绾跨储杞Щ' - case BizTypeEnum.CRM_CUSTOMER: - return '瀹㈡埛杞Щ' - case BizTypeEnum.CRM_CONTACT: - return '鑱旂郴浜鸿浆绉�' - case BizTypeEnum.CRM_BUSINESS: - return '鍟嗘満杞Щ' - case BizTypeEnum.CRM_CONTRACT: - return '鍚堝悓杞Щ' - default: - return '杞Щ' - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formRef.value?.resetFields() - formData.value = {} as TransferReqVO -} -onMounted(async () => { - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() -}) -</script> diff --git a/src/views/crm/product/ProductForm.vue b/src/views/crm/product/ProductForm.vue deleted file mode 100644 index 1bc5aac..0000000 --- a/src/views/crm/product/ProductForm.vue +++ /dev/null @@ -1,212 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-row> - <el-col :span="12"> - <el-form-item label="浜у搧鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - placeholder="璇烽�夋嫨璐熻矗浜�" - :disabled="formData.id" - class="w-1/1" - > - <el-option - v-for="user in userList" - :key="user.id" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浜у搧绫诲瀷" prop="categoryId"> - <el-cascader - v-model="formData.categoryId" - :options="productCategoryList" - :props="defaultProps" - class="w-1/1" - clearable - placeholder="璇烽�夋嫨浜у搧绫诲瀷" - filterable - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浜у搧鍗曚綅" prop="unit"> - <el-select v-model="formData.unit" class="w-1/1" placeholder="璇烽�夋嫨鍗曚綅"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PRODUCT_UNIT)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浜у搧缂栫爜" prop="no"> - <el-input v-model="formData.no" placeholder="璇疯緭鍏ヤ骇鍝佺紪鐮�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浠锋牸" prop="price"> - <el-input-number - v-model="formData.price" - placeholder="璇疯緭鍏ヤ环鏍�" - :min="0" - :precision="2" - :step="0.1" - class="w-full!" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浜у搧鎻忚堪" prop="description"> - <el-input v-model="formData.description" placeholder="璇疯緭鍏ヤ骇鍝佹弿杩�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="涓婃灦鐘舵��" prop="status"> - <el-select v-model="formData.status" placeholder="璇烽�夋嫨鐘舵��" class="w-1/1"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PRODUCT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as ProductApi from '@/api/crm/product' -import * as ProductCategoryApi from '@/api/crm/product/category' -import { defaultProps, handleTree } from '@/utils/tree' -import { getSimpleUserList, UserVO } from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' - -defineOptions({ name: 'CrmProductForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const userId = useUserStore().getUser.id // 褰撳墠鐧诲綍鐨勭紪鍙� -const formData = ref({ - id: undefined, - name: undefined, - no: undefined, - unit: undefined, - price: Number(undefined), - status: undefined, - categoryId: undefined, - description: undefined, - ownerUserId: -1 -}) -const formRules = reactive({ - name: [{ required: true, message: '浜у搧鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - no: [{ required: true, message: '浜у搧缂栫爜涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'change' }], - categoryId: [{ required: true, message: '浜у搧鍒嗙被ID涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }], - price: [{ required: true, message: '浠锋牸涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductApi.getProduct(id) - } finally { - formLoading.value = false - } - } else { - formData.value.ownerUserId = userId - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProductApi.ProductVO - if (formType.value === 'create') { - await ProductApi.createProduct(data) - message.success(t('common.createSuccess')) - } else { - await ProductApi.updateProduct(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - no: undefined, - unit: undefined, - price: Number(undefined), - status: undefined, - categoryId: undefined, - description: undefined, - ownerUserId: -1 - } - formRef.value?.resetFields() -} - -/** 鍒濆鍖� */ -const productCategoryList = ref<any[]>([]) // 浜у搧鍒嗙被鏍� -const userList = ref<UserVO[]>([]) // 绯荤粺鐢ㄦ埛 -onMounted(async () => { - // 浜у搧鍒嗙被鏍� - const data = await ProductCategoryApi.getProductCategoryList({}) - productCategoryList.value = handleTree(data, 'id', 'parentId') - // 绯荤粺鐢ㄦ埛鍒楄〃 - userList.value = await getSimpleUserList() -}) -</script> diff --git a/src/views/crm/product/category/ProductCategoryForm.vue b/src/views/crm/product/category/ProductCategoryForm.vue deleted file mode 100644 index 0373fc3..0000000 --- a/src/views/crm/product/category/ProductCategoryForm.vue +++ /dev/null @@ -1,110 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鐖剁骇鍒嗙被" prop="parentId"> - <el-select v-model="formData.parentId" placeholder="璇烽�夋嫨涓婄骇鍒嗙被"> - <el-option :key="0" label="椤剁骇鍒嗙被" :value="0" /> - <el-option - v-for="item in productCategoryList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as ProductCategoryApi from '@/api/crm/product/category' - -defineOptions({ name: 'CrmProductCategoryForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - parentId: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - parentId: [{ required: true, message: '鐖剁骇鍒嗙被涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const productCategoryList = ref<any[]>([]) // 浜у搧鍒嗙被鏍� - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductCategoryApi.getProductCategory(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱鍒嗙被鏍� - productCategoryList.value = await ProductCategoryApi.getProductCategoryList({ parentId: 0 }) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProductCategoryApi.ProductCategoryVO - if (formType.value === 'create') { - await ProductCategoryApi.createProductCategory(data) - message.success(t('common.createSuccess')) - } else { - await ProductCategoryApi.updateProductCategory(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - parentId: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/crm/product/category/index.vue b/src/views/crm/product/category/index.vue deleted file mode 100644 index 631c170..0000000 --- a/src/views/crm/product/category/index.vue +++ /dev/null @@ -1,139 +0,0 @@ -<template> - <doc-alert title="銆愪骇鍝併�戜骇鍝佺鐞嗐�佷骇鍝佸垎绫�" url="https://doc.iocoder.cn/crm/product/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['crm:product-category:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" row-key="id" default-expand-all> - <el-table-column label="鍒嗙被缂栧彿" align="center" prop="id" /> - <el-table-column label="鍒嗙被鍚嶇О" align="center" prop="name" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['crm:product-category:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['crm:product-category:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductCategoryForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as ProductCategoryApi from '@/api/crm/product/category' -import ProductCategoryForm from './ProductCategoryForm.vue' -import { handleTree } from '@/utils/tree' - -defineOptions({ name: 'CrmProductCategory' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - name: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductCategoryApi.getProductCategoryList(queryParams) - list.value = handleTree(data, 'id', 'parentId') - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductCategoryApi.deleteProductCategory(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/product/detail/ProductDetailsHeader.vue b/src/views/crm/product/detail/ProductDetailsHeader.vue deleted file mode 100644 index 11286d6..0000000 --- a/src/views/crm/product/detail/ProductDetailsHeader.vue +++ /dev/null @@ -1,46 +0,0 @@ -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ product.name }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <el-button @click="openForm('update', product.id)" v-hasPermi="['crm:product:update']"> - 缂栬緫 - </el-button> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="浜у搧绫诲埆">{{ product.categoryName }}</el-descriptions-item> - <el-descriptions-item label="浜у搧鍗曚綅"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="product.unit" /> - </el-descriptions-item> - <el-descriptions-item label="浜у搧浠锋牸"> - {{ erpPriceInputFormatter(product.price) }} 鍏� - </el-descriptions-item> - <el-descriptions-item label="浜у搧缂栫爜">{{ product.no }}</el-descriptions-item> - </el-descriptions> - </ContentWrap> - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductForm ref="formRef" @success="emit('refresh')" /> -</template> -<script setup lang="ts"> -import ProductForm from '@/views/crm/product/ProductForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { erpPriceInputFormatter } from '@/utils' -import * as ProductApi from '@/api/crm/product' - -// 鎿嶄綔淇敼 -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} -const { product } = defineProps<{ product: ProductApi.ProductVO }>() -</script> diff --git a/src/views/crm/product/detail/ProductDetailsInfo.vue b/src/views/crm/product/detail/ProductDetailsInfo.vue deleted file mode 100644 index 52a11e9..0000000 --- a/src/views/crm/product/detail/ProductDetailsInfo.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="浜у搧鍚嶇О">{{ product.name }}</el-descriptions-item> - <el-descriptions-item label="浜у搧缂栫爜">{{ product.no }}</el-descriptions-item> - <el-descriptions-item label="浠锋牸"> - {{ erpPriceInputFormatter(product.price) }} 鍏� - </el-descriptions-item> - <el-descriptions-item label="浜у搧鎻忚堪">{{ product.description }}</el-descriptions-item> - <el-descriptions-item label="浜у搧绫诲瀷">{{ product.categoryName }}</el-descriptions-item> - <el-descriptions-item label="鏄惁涓婁笅鏋�"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_STATUS" :value="product.status" /> - </el-descriptions-item> - <el-descriptions-item label="鍗曚綅"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="product.unit" /> - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import * as ProductApi from '@/api/crm/product' -import { erpPriceInputFormatter } from '@/utils' - -const { product } = defineProps<{ - product: ProductApi.ProductVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['basicInfo']) -</script> diff --git a/src/views/crm/product/detail/index.vue b/src/views/crm/product/detail/index.vue deleted file mode 100644 index ff9efd9..0000000 --- a/src/views/crm/product/detail/index.vue +++ /dev/null @@ -1,66 +0,0 @@ -<template> - <ProductDetailsHeader :loading="loading" :product="product" @refresh="getProductData(id)" /> - <el-col> - <el-tabs> - <el-tab-pane label="璇︾粏璧勬枡"> - <ProductDetailsInfo :product="product" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import { OperateLogVO } from '@/api/system/operatelog' -import * as ProductApi from '@/api/crm/product' -import ProductDetailsHeader from '@/views/crm/product/detail/ProductDetailsHeader.vue' -import ProductDetailsInfo from '@/views/crm/product/detail/ProductDetailsInfo.vue' -import { BizTypeEnum } from '@/api/crm/permission' -import { getOperateLogPage } from '@/api/crm/operateLog' - -defineOptions({ name: 'CrmProductDetail' }) - -const route = useRoute() -const message = useMessage() -const id = Number(route.params.id) // 缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const product = ref<ProductApi.ProductVO>({} as ProductApi.ProductVO) // 璇︽儏 - -/** 鑾峰彇璇︽儏 */ -const getProductData = async (id: number) => { - loading.value = true - try { - product.value = await ProductApi.getProduct(id) - await getOperateLog(id) - } finally { - loading.value = false - } -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (productId: number) => { - if (!productId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_PRODUCT, - bizId: productId - }) - logList.value = data.list -} - -/** 鍒濆鍖� */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -onMounted(async () => { - if (!id) { - message.warning('鍙傛暟閿欒锛屼骇鍝佷笉鑳戒负绌猴紒') - delView(unref(currentRoute)) - return - } - await getProductData(id) -}) -</script> diff --git a/src/views/crm/product/index.vue b/src/views/crm/product/index.vue deleted file mode 100644 index 5d656df..0000000 --- a/src/views/crm/product/index.vue +++ /dev/null @@ -1,230 +0,0 @@ -<template> - <doc-alert title="銆愪骇鍝併�戜骇鍝佺鐞嗐�佷骇鍝佸垎绫�" url="https://doc.iocoder.cn/crm/product/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="浜у搧鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PRODUCT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" /> 鎼滅储 </el-button> - <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆 </el-button> - <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:product:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['crm:product:export']" - > - <Icon icon="ep:download" class="mr-5px" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="浜у搧鍚嶇О" align="center" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column label="浜у搧绫诲瀷" align="center" prop="categoryName" width="160" /> - <el-table-column label="浜у搧鍗曚綅" align="center" prop="unit"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.unit" /> - </template> - </el-table-column> - <el-table-column label="浜у搧缂栫爜" align="center" prop="no" /> - <el-table-column - label="浠锋牸锛堝厓锛�" - align="center" - prop="price" - :formatter="erpPriceTableColumnFormatter" - width="100" - /> - <el-table-column label="浜у搧鎻忚堪" align="center" prop="description" width="150" /> - <el-table-column label="涓婃灦鐘舵��" align="center" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_PRODUCT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="璐熻矗浜�" align="center" prop="ownerUserName" width="120" /> - <el-table-column - label="鏇存柊鏃堕棿" - align="center" - prop="updateTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" width="120" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="160"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['crm:product:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['crm:product:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ProductApi from '@/api/crm/product' -import ProductForm from './ProductForm.vue' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CrmProduct' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductApi.getProductPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鎵撳紑璇︽儏 */ -const { currentRoute, push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmProductDetail', params: { id } }) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductApi.deleteProduct(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ProductApi.exportProduct(queryParams) - download.excel(data, '浜у搧.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 婵�娲绘椂 */ -onActivated(() => { - getList() -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/crm/receivable/ReceivableForm.vue b/src/views/crm/receivable/ReceivableForm.vue deleted file mode 100644 index a44164a..0000000 --- a/src/views/crm/receivable/ReceivableForm.vue +++ /dev/null @@ -1,293 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="鍥炴缂栧彿" prop="no"> - <el-input v-model="formData.no" disabled placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - v-model="formData.customerId" - :disabled="formType !== 'create'" - class="w-1/1" - filterable - placeholder="璇烽�夋嫨瀹㈡埛" - @change="handleCustomerChange" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍚堝悓鍚嶇О" prop="contractId"> - <el-select - v-model="formData.contractId" - :disabled="formType !== 'create' || !formData.customerId" - class="w-1/1" - filterable - placeholder="璇烽�夋嫨鍚堝悓" - @change="handleContractChange" - > - <el-option - v-for="data in contractList" - :key="data.id" - :disabled="data.auditStatus !== 20" - :label="data.name" - :value="data.id!" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍥炴鏈熸暟" prop="planId"> - <el-select - v-model="formData.planId" - :disabled="formType !== 'create' || !formData.contractId" - class="!w-1/1" - placeholder="璇烽�夋嫨鍥炴鏈熸暟" - @change="handleReceivablePlanChange" - > - <el-option - v-for="data in receivablePlanList" - :key="data.id" - :disabled="data.receivableId" - :label="'绗� ' + data.period + ' 鏈�'" - :value="data.id!" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍥炴鏂瑰紡" prop="returnType"> - <el-select v-model="formData.returnType" class="w-1/1" placeholder="璇烽�夋嫨鍥炴鏂瑰紡"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍥炴閲戦" prop="price"> - <el-input-number - v-model="formData.price" - :min="0.01" - :precision="2" - class="!w-100%" - controls-position="right" - placeholder="璇疯緭鍏ュ洖娆鹃噾棰�" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍥炴鏃ユ湡" prop="returnTime"> - <el-date-picker - v-model="formData.returnTime" - placeholder="閫夋嫨鍥炴鏃ユ湡" - type="date" - value-format="x" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="24"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import * as ReceivableApi from '@/api/crm/receivable' -import { ReceivableVO } from '@/api/crm/receivable' -import * as UserApi from '@/api/system/user' -import * as CustomerApi from '@/api/crm/customer' -import * as ContractApi from '@/api/crm/contract' -import { useUserStore } from '@/store/modules/user' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref<ReceivableApi.ReceivableVO>({} as ReceivableApi.ReceivableVO) -const formRules = reactive({ - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - contractId: [{ required: true, message: '鍚堝悓涓嶈兘涓虹┖', trigger: 'blur' }], - returnTime: [{ required: true, message: '鍥炴鏃ユ湡涓嶈兘涓虹┖', trigger: 'blur' }], - price: [{ required: true, message: '鍥炴閲戦涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const contractList = ref<ContractApi.ContractVO[]>([]) // 鍚堝悓鍒楄〃 -const receivablePlanList = ref<ReceivablePlanApi.ReceivablePlanVO[]>([]) // 鍥炴璁″垝鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async ( - type: string, - id?: number, - receivablePlan?: ReceivablePlanApi.ReceivablePlanVO -) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = (await ReceivableApi.getReceivable(id)) as ReceivableVO - formData.value = data - await handleCustomerChange(data.customerId!) - formData.value.contractId = data?.contract?.id - } finally { - formLoading.value = false - } - } - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } - // 浠庡洖娆捐鍒掑垱寤哄洖娆� - if (receivablePlan) { - formData.value.customerId = receivablePlan.customerId - await handleCustomerChange(receivablePlan.customerId) - formData.value.contractId = receivablePlan.contractId - await handleContractChange(receivablePlan.contractId) - if (receivablePlan.id) { - formData.value.planId = receivablePlan.id - formData.value.price = receivablePlan.price - formData.value.returnType = receivablePlan.returnType - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ReceivableApi.ReceivableVO - if (formType.value === 'create') { - await ReceivableApi.createReceivable(data) - message.success(t('common.createSuccess')) - } else { - await ReceivableApi.updateReceivable(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = {} as ReceivableApi.ReceivableVO - formRef.value?.resetFields() -} - -/** 澶勭悊鍒囨崲瀹㈡埛 */ -const handleCustomerChange = async (customerId: number) => { - // 閲嶇疆鍚堝悓缂栧彿 - formData.value.contractId = undefined - // 鑾峰緱鍚堝悓鍒楄〃 - if (customerId) { - contractList.value = [] - contractList.value = await ContractApi.getContractSimpleList(customerId) - } -} - -/** 澶勭悊鍒囨崲鍚堝悓 */ -const handleContractChange = async (contractId: number) => { - // 閲嶇疆鍥炴璁″垝缂栧彿 - formData.value.planId = undefined - if (contractId) { - // 鑾峰緱鍥炴璁″垝鍒楄〃 - receivablePlanList.value = [] - receivablePlanList.value = await ReceivablePlanApi.getReceivablePlanSimpleList( - formData.value.customerId!, - contractId - ) - // 璁剧疆閲戦 - const contract = contractList.value.find((item) => item.id === contractId) - if (contract) { - formData.value.price = contract.totalPrice - contract.totalReceivablePrice - } - } -} - -/** 澶勭悊鍒囨崲鍥炴璁″垝 */ -const handleReceivablePlanChange = (planId: number) => { - if (!planId) { - return - } - const receivablePlan = receivablePlanList.value.find((item) => item.id === planId) - if (!receivablePlan) { - return - } - formData.value.price = receivablePlan.price - formData.value.returnType = receivablePlan.returnType -} -</script> diff --git a/src/views/crm/receivable/components/ReceivableList.vue b/src/views/crm/receivable/components/ReceivableList.vue deleted file mode 100644 index 67287ea..0000000 --- a/src/views/crm/receivable/components/ReceivableList.vue +++ /dev/null @@ -1,164 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row justify="end"> - <el-button @click="openForm('create')"> - <Icon class="mr-5px" icon="icon-park:income-one" /> - 鍒涘缓鍥炴 - </el-button> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="鍥炴缂栧彿" prop="no" /> - <el-table-column align="center" label="瀹㈡埛" prop="customerName" /> - <el-table-column align="center" label="鍚堝悓" prop="contract.no" /> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="鍥炴鏃ユ湡" - prop="returnTime" - width="150px" - /> - <el-table-column align="center" label="鍥炴鏂瑰紡" prop="returnType" width="130px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="scope.row.returnType" /> - </template> - </el-table-column> - <el-table-column - align="center" - label="鍥炴閲戦(鍏�)" - prop="price" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" /> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="130px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:receivable:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <ReceivableForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import * as ReceivableApi from '@/api/crm/receivable' -import ReceivableForm from './../ReceivableForm.vue' -import { dateFormatter2 } from '@/utils/formatTime' -import { DICT_TYPE } from '@/utils/dict' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CrmReceivableList' }) -const props = defineProps<{ - customerId?: number // 瀹㈡埛缂栧彿 - contractId?: number // 鍚堝悓缂栧彿 -}>() - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - customerId: undefined as unknown, // 鍏佽 undefined + number - contractId: undefined as unknown // 鍏佽 undefined + number -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - if (props.customerId && !props.contractId) { - queryParams.customerId = props.customerId - } else if (props.customerId && props.contractId) { - // 濡傛灉鏄悎鍚岀殑璇濆鎴风紪鍙蜂篃闇�瑕佸甫涓婂洜涓烘潈闄愬熀浜庡鎴� - queryParams.customerId = props.customerId - queryParams.contractId = props.contractId - } - const data = await ReceivableApi.getReceivablePageByCustomer(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - // 缃┖鍙傛暟 - queryParams.customerId = undefined - queryParams.contractId = undefined - getList() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id, { - customerId: props.customerId, - contractId: props.contractId - }) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ReceivableApi.deleteReceivable(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 浠庡洖娆捐鍒掑垱寤哄洖娆� */ -const createReceivable = (planData: any) => { - const data = planData as unknown as ReceivablePlanApi.ReceivablePlanVO - formRef.value.open('create', undefined, data) -} -defineExpose({ createReceivable }) - -/** 鐩戝惉鎵撳紑鐨� customerId + contractId锛屼粠鑰屽姞杞芥渶鏂扮殑鍒楄〃 */ -watch( - () => [props.customerId, props.contractId], - (newVal) => { - // 淇濊瘉鑷冲皯瀹㈡埛缂栧彿鏈夊�� - if (!newVal[0]) { - return - } - handleQuery() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/receivable/detail/ReceivableDetailsHeader.vue b/src/views/crm/receivable/detail/ReceivableDetailsHeader.vue deleted file mode 100644 index 62201de..0000000 --- a/src/views/crm/receivable/detail/ReceivableDetailsHeader.vue +++ /dev/null @@ -1,43 +0,0 @@ -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">{{ receivable.no }}</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ receivable.customerName }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓閲戦"> - {{ erpPriceInputFormatter(receivable.contract?.totalPrice) }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴鏃ユ湡"> - {{ formatDate(receivable.returnTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴閲戦"> - {{ erpPriceInputFormatter(receivable.price) }} - </el-descriptions-item> - <el-descriptions-item label="璐熻矗浜�"> - {{ receivable.ownerUserName }} - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ReceivableApi from '@/api/crm/receivable' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { receivable } = defineProps<{ receivable: ReceivableApi.ReceivableVO }>() -</script> diff --git a/src/views/crm/receivable/detail/ReceivableDetailsInfo.vue b/src/views/crm/receivable/detail/ReceivableDetailsInfo.vue deleted file mode 100644 index 003029f..0000000 --- a/src/views/crm/receivable/detail/ReceivableDetailsInfo.vue +++ /dev/null @@ -1,62 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="鍥炴缂栧彿">{{ receivable.no }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ receivable.customerName }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓缂栧彿"> - {{ receivable.contract?.no }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴鏃ユ湡"> - {{ formatDate(receivable.returnTime, 'YYYY-MM-DD') }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴閲戦"> - {{ erpPriceInputFormatter(receivable.price) }} - </el-descriptions-item> - <el-descriptions-item label="鍥炴鏂瑰紡"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="receivable.returnType" /> - </el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ receivable.remark }}</el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�"> - {{ receivable.ownerUserName }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�"> - {{ receivable.creatorName }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(receivable.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(receivable.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ReceivableApi from '@/api/crm/receivable' -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { receivable } = defineProps<{ - receivable: ReceivableApi.ReceivableVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['basicInfo', 'systemInfo']) -</script> diff --git a/src/views/crm/receivable/detail/index.vue b/src/views/crm/receivable/detail/index.vue deleted file mode 100644 index 3603572..0000000 --- a/src/views/crm/receivable/detail/index.vue +++ /dev/null @@ -1,100 +0,0 @@ -<template> - <ReceivableDetailsHeader v-loading="loading" :receivable="receivable"> - <el-button v-if="permissionListRef?.validateWrite" @click="openForm('update', receivable.id)"> - 缂栬緫 - </el-button> - </ReceivableDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璇︾粏璧勬枡"> - <ReceivableDetailsInfo :receivable="receivable" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="receivable.id!" - :biz-type="BizTypeEnum.CRM_RECEIVABLE" - :show-action="true" - @quit-team="close" - /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ReceivableForm ref="formRef" @success="getReceivable(receivable.id)" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as ReceivableApi from '@/api/crm/receivable' -import ReceivableDetailsHeader from './ReceivableDetailsHeader.vue' -import ReceivableDetailsInfo from './ReceivableDetailsInfo.vue' -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import { BizTypeEnum } from '@/api/crm/permission' -import { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' -import ReceivableForm from '@/views/crm/receivable/ReceivableForm.vue' - -defineOptions({ name: 'CrmReceivablePlanDetail' }) -const props = defineProps<{ id?: number }>() - -const route = useRoute() -const message = useMessage() -const receivableId = ref(0) // 鍥炴缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const receivable = ref<ReceivableApi.ReceivableVO>({} as ReceivableApi.ReceivableVO) // 鍥炴璇︽儏 -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const getReceivable = async (id: number) => { - loading.value = true - try { - receivable.value = await ReceivableApi.getReceivable(id) - await getOperateLog(id) - } finally { - loading.value = false - } -} - -/** 缂栬緫 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (receivableId: number) => { - if (!receivableId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_RECEIVABLE, - bizId: receivableId - }) - logList.value = data.list -} - -/** 鍏抽棴绐楀彛 */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(async () => { - const id = props.id || route.params.id - if (!id) { - message.warning('鍙傛暟閿欒锛屽洖娆句笉鑳戒负绌猴紒') - close() - return - } - receivableId.value = id - await getReceivable(receivableId.value) -}) -</script> diff --git a/src/views/crm/receivable/index.vue b/src/views/crm/receivable/index.vue deleted file mode 100644 index 6928942..0000000 --- a/src/views/crm/receivable/index.vue +++ /dev/null @@ -1,335 +0,0 @@ -<template> - <doc-alert title="銆愬洖娆俱�戝洖娆剧鐞嗐�佸洖娆捐鍒�" url="https://doc.iocoder.cn/crm/receivable/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍥炴缂栧彿" prop="no"> - <el-input - v-model="queryParams.no" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ洖娆剧紪鍙�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - v-model="queryParams.customerId" - class="!w-240px" - placeholder="璇烽�夋嫨瀹㈡埛" - @keyup.enter="handleQuery" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['crm:receivable:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['crm:receivable:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="鎴戝弬涓庣殑" name="2" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="鍥炴缂栧彿" prop="no" width="180"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.no }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍚堝悓缂栧彿" prop="contractNo" width="180"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openContractDetail(scope.row.contractId)" - > - {{ scope.row.contract.no }} - </el-link> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="鍥炴鏃ユ湡" - prop="returnTime" - width="150px" - /> - <el-table-column - align="center" - label="鍥炴閲戦(鍏�)" - prop="price" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="鍥炴鏂瑰紡" prop="returnType" width="130px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="scope.row.returnType" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - align="center" - label="鍚堝悓閲戦锛堝厓锛�" - prop="contract.totalPrice" - width="140" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="120" /> - <el-table-column align="center" fixed="right" label="鍥炴鐘舵��" prop="auditStatus" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="180px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-if="scope.row.auditStatus === 0" - v-hasPermi="['crm:receivable:update']" - link - type="primary" - @click="handleSubmit(scope.row)" - > - 鎻愪氦瀹℃牳 - </el-button> - <el-button - v-else - v-hasPermi="['crm:receivable:update']" - link - type="primary" - @click="handleProcessDetail(scope.row)" - > - 鏌ョ湅瀹℃壒 - </el-button> - <el-button - v-hasPermi="['crm:receivable:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ReceivableForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ReceivableApi from '@/api/crm/receivable' -import ReceivableForm from './ReceivableForm.vue' -import * as CustomerApi from '@/api/crm/customer' -import { TabsPaneContext } from 'element-plus' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'Receivable' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - no: undefined, - customerId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ReceivableApi.getReceivablePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ReceivableApi.deleteReceivable(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎻愪氦瀹℃牳 **/ -const handleSubmit = async (row: ReceivableApi.ReceivableVO) => { - await message.confirm(`鎮ㄧ‘瀹氭彁浜ょ紪鍙蜂负銆�${row.no}銆戠殑鍥炴瀹℃牳鍚楋紵`) - await ReceivableApi.submitReceivable(row.id) - message.success('鎻愪氦瀹℃牳鎴愬姛锛�') - await getList() -} - -/** 鏌ョ湅瀹℃壒 */ -const handleProcessDetail = (row: ReceivableApi.ReceivableVO) => { - push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }) -} - -/** 鎵撳紑鍥炴璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmReceivableDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鎵撳紑鍚堝悓璇︽儏 */ -const openContractDetail = (id: number) => { - push({ name: 'CrmContractDetail', params: { id } }) -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ReceivableApi.exportReceivable(queryParams) - download.excel(data, '鍥炴.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() -}) -</script> diff --git a/src/views/crm/receivable/plan/ReceivablePlanForm.vue b/src/views/crm/receivable/plan/ReceivablePlanForm.vue deleted file mode 100644 index 0d4ef17..0000000 --- a/src/views/crm/receivable/plan/ReceivablePlanForm.vue +++ /dev/null @@ -1,239 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="杩樻鏈熸暟" prop="period"> - <el-input v-model="formData.period" disabled placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璐熻矗浜�" prop="ownerUserId"> - <el-select - v-model="formData.ownerUserId" - :disabled="formType !== 'create'" - class="w-1/1" - > - <el-option - v-for="item in userOptions" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - v-model="formData.customerId" - :disabled="formType !== 'create'" - class="w-1/1" - filterable - placeholder="璇烽�夋嫨瀹㈡埛" - @change="handleCustomerChange" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍚堝悓鍚嶇О" prop="contractId"> - <el-select - v-model="formData.contractId" - :disabled="formType !== 'create' || !formData.customerId" - class="w-1/1" - filterable - placeholder="璇烽�夋嫨鍚堝悓" - > - <el-option - v-for="data in contractList" - :key="data.id" - :label="data.name" - :value="data.id!" - /> - </el-select> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="璁″垝鍥炴閲戦" prop="price"> - <el-input-number - v-model="formData.price" - :min="0.01" - :precision="2" - class="!w-100%" - controls-position="right" - placeholder="璇疯緭鍏ヨ鍒掑洖娆鹃噾棰�" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="璁″垝鍥炴鏃ユ湡" prop="returnTime"> - <el-date-picker - v-model="formData.returnTime" - placeholder="閫夋嫨璁″垝鍥炴鏃ユ湡" - type="date" - value-format="x" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鎻愬墠鍑犲ぉ鎻愰啋" prop="remindDays"> - <el-input-number - v-model="formData.remindDays" - class="!w-100%" - controls-position="right" - placeholder="璇疯緭鍏ユ彁鍓嶅嚑澶╂彁閱�" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍥炴鏂瑰紡" prop="returnType"> - <el-select v-model="formData.returnType" class="w-1/1" placeholder="璇烽�夋嫨鍥炴鏂瑰紡"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import * as UserApi from '@/api/system/user' -import * as CustomerApi from '@/api/crm/customer' -import * as ContractApi from '@/api/crm/contract' -import { useUserStore } from '@/store/modules/user' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { cloneDeep } from 'lodash-es' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const userOptions = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref<ReceivablePlanApi.ReceivablePlanVO>({} as ReceivablePlanApi.ReceivablePlanVO) -const formRules = reactive({ - price: [{ required: true, message: '璁″垝鍥炴閲戦涓嶈兘涓虹┖', trigger: 'blur' }], - returnTime: [{ required: true, message: '璁″垝鍥炴鏃ユ湡涓嶈兘涓虹┖', trigger: 'blur' }], - customerId: [{ required: true, message: '瀹㈡埛缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - contractId: [{ required: true, message: '鍚堝悓缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '璐熻矗浜轰笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const contractList = ref<ContractApi.ContractVO[]>([]) // 鍚堝悓鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number, customerId?: number, contractId?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = await ReceivablePlanApi.getReceivablePlan(id) - formData.value = cloneDeep(data) - await handleCustomerChange(data.customerId!) - formData.value.contractId = data?.contractId - } finally { - formLoading.value = false - } - } - // 鑾峰緱鐢ㄦ埛鍒楄〃 - userOptions.value = await UserApi.getSimpleUserList() - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 榛樿鏂板缓鏃堕�変腑鑷繁 - if (formType.value === 'create') { - formData.value.ownerUserId = useUserStore().getUser.id - } - // 璁剧疆 customerId 鍜� contractId 榛樿鍊� - if (customerId) { - formData.value.customerId = customerId - await handleCustomerChange(customerId) - } - if (contractId) { - formData.value.contractId = contractId - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ReceivablePlanApi.ReceivablePlanVO - if (formType.value === 'create') { - await ReceivablePlanApi.createReceivablePlan(data) - message.success(t('common.createSuccess')) - } else { - await ReceivablePlanApi.updateReceivablePlan(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = {} as ReceivablePlanApi.ReceivablePlanVO - formRef.value?.resetFields() -} - -/** 澶勭悊鍒囨崲瀹㈡埛 */ -const handleCustomerChange = async (customerId: number) => { - // 閲嶇疆鍚堝悓缂栧彿 - formData.value.contractId = undefined - // 鑾峰緱鍚堝悓鍒楄〃 - if (customerId) { - contractList.value = [] - contractList.value = await ContractApi.getContractSimpleList(customerId) - } -} -</script> diff --git a/src/views/crm/receivable/plan/components/ReceivablePlanList.vue b/src/views/crm/receivable/plan/components/ReceivablePlanList.vue deleted file mode 100644 index 3b80526..0000000 --- a/src/views/crm/receivable/plan/components/ReceivablePlanList.vue +++ /dev/null @@ -1,173 +0,0 @@ -<template> - <!-- 鎿嶄綔鏍� --> - <el-row justify="end"> - <el-button @click="openForm('create', undefined)"> - <Icon class="mr-5px" icon="icon-park:income" /> - 鍒涘缓鍥炴璁″垝 - </el-button> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap class="mt-10px"> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="瀹㈡埛鍚嶇О" prop="customerName" width="150px" /> - <el-table-column align="center" label="鍚堝悓缂栧彿" prop="contractNo" width="200px" /> - <el-table-column align="center" label="鏈熸暟" prop="period" /> - <el-table-column - align="center" - label="璁″垝鍥炴(鍏�)" - prop="price" - width="120" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="璁″垝鍥炴鏃ユ湡" - prop="returnTime" - width="180px" - /> - <el-table-column align="center" label="鎻愬墠鍑犲ぉ鎻愰啋" prop="remindDays" width="150" /> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="鎻愰啋鏃ユ湡" - prop="remindTime" - width="180px" - /> - <el-table-column label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="200px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:create']" - link - type="primary" - @click="createReceivable(scope.row)" - :disabled="scope.row.receivableId" - > - 鍒涘缓鍥炴 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <ReceivableForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import ReceivableForm from './../ReceivablePlanForm.vue' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CrmReceivablePlanList' }) -const props = defineProps<{ - customerId?: number // 瀹㈡埛缂栧彿 - contractId?: number // 鍚堝悓缂栧彿 -}>() - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - customerId: undefined as unknown, // 鍏佽 undefined + number - contractId: undefined as unknown // 鍏佽 undefined + number -}) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - if (props.customerId && !props.contractId) { - queryParams.customerId = props.customerId - } else if (props.customerId && props.contractId) { - // 濡傛灉鏄悎鍚岀殑璇濆鎴风紪鍙蜂篃闇�瑕佸甫涓婂洜涓烘潈闄愬熀浜庡鎴� - queryParams.customerId = props.customerId - queryParams.contractId = props.contractId - } - const data = await ReceivablePlanApi.getReceivablePlanPageByCustomer(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - // 缃┖鍙傛暟 - queryParams.customerId = undefined - queryParams.contractId = undefined - getList() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id, props.customerId, props.contractId) -} - -/** 鍒涘缓鍥炴 */ -const emits = defineEmits<{ - (e: 'createReceivable', v: ReceivablePlanApi.ReceivablePlanVO) -}>() -const createReceivable = (row: ReceivablePlanApi.ReceivablePlanVO) => { - emits('createReceivable', row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ReceivablePlanApi.deleteReceivablePlan(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鐩戝惉鎵撳紑鐨� customerId + contractId锛屼粠鑰屽姞杞芥渶鏂扮殑鍒楄〃 */ -watch( - () => [props.customerId, props.contractId], - (newVal) => { - // 淇濊瘉鑷冲皯瀹㈡埛缂栧彿鏈夊�� - if (!newVal[0]) { - return - } - handleQuery() - }, - { immediate: true, deep: true } -) -</script> diff --git a/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsHeader.vue b/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsHeader.vue deleted file mode 100644 index b0e0044..0000000 --- a/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsHeader.vue +++ /dev/null @@ -1,44 +0,0 @@ -<template> - <div> - <div class="flex items-start justify-between"> - <div> - <el-col> - <el-row> - <span class="text-xl font-bold">绗� {{ receivablePlan.period }} 鏈�</span> - </el-row> - </el-col> - </div> - <div> - <!-- 鍙充笂锛氭寜閽� --> - <slot></slot> - </div> - </div> - </div> - <ContentWrap class="mt-10px"> - <el-descriptions :column="5" direction="vertical"> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ receivablePlan.customerName }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓缂栧彿">{{ receivablePlan.contractNo }}</el-descriptions-item> - <el-descriptions-item label="璁″垝鍥炴閲戦"> - {{ erpPriceInputFormatter(receivablePlan.price) }} - </el-descriptions-item> - <el-descriptions-item label="璁″垝鍥炴鏃ユ湡"> - {{ formatDate(receivablePlan.returnTime) }} - </el-descriptions-item> - <el-descriptions-item label="瀹為檯鍥炴閲戦"> - <el-text v-if="receivablePlan.receivable"> - {{ erpPriceInputFormatter(receivablePlan.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(0) }}</el-text> - </el-descriptions-item> - </el-descriptions> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { receivablePlan } = defineProps<{ receivablePlan: ReceivablePlanApi.ReceivablePlanVO }>() -</script> diff --git a/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsInfo.vue b/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsInfo.vue deleted file mode 100644 index c25259b..0000000 --- a/src/views/crm/receivable/plan/detail/ReceivablePlanDetailsInfo.vue +++ /dev/null @@ -1,83 +0,0 @@ -<template> - <ContentWrap> - <el-collapse v-model="activeNames"> - <el-collapse-item name="basicInfo"> - <template #title> - <span class="text-base font-bold">鍩烘湰淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="鏈熸暟">{{ receivablePlan.period }}</el-descriptions-item> - <el-descriptions-item label="瀹㈡埛鍚嶇О"> - {{ receivablePlan.customerName }} - </el-descriptions-item> - <el-descriptions-item label="鍚堝悓缂栧彿"> - {{ receivablePlan.contractNo }} - </el-descriptions-item> - <el-descriptions-item label="璁″垝鍥炴閲戦"> - {{ erpPriceInputFormatter(receivablePlan.price) }} - </el-descriptions-item> - <el-descriptions-item label="璁″垝鍥炴鏃ユ湡"> - {{ formatDate(receivablePlan.returnTime, 'YYYY-MM-DD') }} - </el-descriptions-item> - <el-descriptions-item label="璁″垝鍥炴鏂瑰紡"> - <dict-tag - :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" - :value="receivablePlan.returnType" - /> - </el-descriptions-item> - <el-descriptions-item label="鎻愬墠鍑犲ぉ鎻愰啋"> - {{ receivablePlan.remindDays }} - </el-descriptions-item> - <el-descriptions-item label="澶囨敞">{{ receivablePlan.remark }}</el-descriptions-item> - <el-descriptions-item label="瀹為檯鍥炴閲戦"> - <el-text v-if="receivablePlan.receivable"> - {{ erpPriceInputFormatter(receivablePlan.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(0) }}</el-text> - </el-descriptions-item> - <el-descriptions-item label="鏈洖娆鹃噾棰�"> - <el-text v-if="receivablePlan.receivable"> - {{ erpPriceInputFormatter(receivablePlan.price - receivablePlan.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(receivablePlan.price) }}</el-text> - </el-descriptions-item> - <el-descriptions-item label="瀹為檯鍥炴鏃ユ湡"> - {{ formatDate(receivablePlan.receivable?.returnTime, 'YYYY-MM-DD') }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - <el-collapse-item name="systemInfo"> - <template #title> - <span class="text-base font-bold">绯荤粺淇℃伅</span> - </template> - <el-descriptions :column="4"> - <el-descriptions-item label="璐熻矗浜�"> - {{ receivablePlan.ownerUserName }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓浜�"> - {{ receivablePlan.creatorName }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(receivablePlan.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(receivablePlan.updateTime) }} - </el-descriptions-item> - </el-descriptions> - </el-collapse-item> - </el-collapse> - </ContentWrap> -</template> -<script setup lang="ts"> -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import { erpPriceInputFormatter } from '@/utils' - -const { receivablePlan } = defineProps<{ - receivablePlan: ReceivablePlanApi.ReceivablePlanVO -}>() - -// 灞曠ず鐨勬姌鍙犻潰鏉� -const activeNames = ref(['basicInfo', 'systemInfo']) -</script> diff --git a/src/views/crm/receivable/plan/detail/index.vue b/src/views/crm/receivable/plan/detail/index.vue deleted file mode 100644 index fba8694..0000000 --- a/src/views/crm/receivable/plan/detail/index.vue +++ /dev/null @@ -1,103 +0,0 @@ -<template> - <ReceivablePlanDetailsHeader v-loading="loading" :receivable-plan="receivablePlan"> - <el-button - v-if="permissionListRef?.validateWrite" - @click="openForm('update', receivablePlan.id)" - > - 缂栬緫 - </el-button> - </ReceivablePlanDetailsHeader> - <el-col> - <el-tabs> - <el-tab-pane label="璇︾粏璧勬枡"> - <ReceivablePlanDetailsInfo :receivable-plan="receivablePlan" /> - </el-tab-pane> - <el-tab-pane label="鎿嶄綔鏃ュ織"> - <OperateLogV2 :log-list="logList" /> - </el-tab-pane> - <el-tab-pane label="鍥㈤槦鎴愬憳"> - <PermissionList - ref="permissionListRef" - :biz-id="receivablePlan.id!" - :biz-type="BizTypeEnum.CRM_RECEIVABLE_PLAN" - :show-action="true" - @quit-team="close" - /> - </el-tab-pane> - </el-tabs> - </el-col> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ReceivablePlanForm ref="formRef" @success="getReceivablePlan(receivablePlan.id)" /> -</template> -<script lang="ts" setup> -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import ReceivablePlanDetailsHeader from './ReceivablePlanDetailsHeader.vue' -import ReceivablePlanDetailsInfo from './ReceivablePlanDetailsInfo.vue' -import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 鍥㈤槦鎴愬憳鍒楄〃锛堟潈闄愶級 -import { BizTypeEnum } from '@/api/crm/permission' -import { OperateLogVO } from '@/api/system/operatelog' -import { getOperateLogPage } from '@/api/crm/operateLog' -import ReceivablePlanForm from '@/views/crm/receivable/plan/ReceivablePlanForm.vue' - -defineOptions({ name: 'CrmReceivablePlanDetail' }) - -const message = useMessage() - -const receivablePlanId = ref(0) // 鍥炴璁″垝缂栧彿 -const loading = ref(true) // 鍔犺浇涓� -const receivablePlan = ref<ReceivablePlanApi.ReceivablePlanVO>( - {} as ReceivablePlanApi.ReceivablePlanVO -) // 鍥炴璁″垝璇︽儏 -const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 鍥㈤槦鎴愬憳鍒楄〃 Ref - -/** 鑾峰彇璇︽儏 */ -const getReceivablePlan = async (id: number) => { - loading.value = true - try { - receivablePlan.value = await ReceivablePlanApi.getReceivablePlan(id) - await getOperateLog(id) - } finally { - loading.value = false - } -} - -/** 缂栬緫 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鑾峰彇鎿嶄綔鏃ュ織 */ -const logList = ref<OperateLogVO[]>([]) // 鎿嶄綔鏃ュ織鍒楄〃 -const getOperateLog = async (receivablePlanId: number) => { - if (!receivablePlanId) { - return - } - const data = await getOperateLogPage({ - bizType: BizTypeEnum.CRM_RECEIVABLE_PLAN, - bizId: receivablePlanId - }) - logList.value = data.list -} - -/** 鍏抽棴绐楀彛 */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) -} - -/** 鍒濆鍖� */ -const { params } = useRoute() -onMounted(async () => { - if (!params.id) { - message.warning('鍙傛暟閿欒锛屽洖娆捐鍒掍笉鑳戒负绌猴紒') - close() - return - } - receivablePlanId.value = params.id as unknown as number - await getReceivablePlan(receivablePlanId.value) -}) -</script> diff --git a/src/views/crm/receivable/plan/index.vue b/src/views/crm/receivable/plan/index.vue deleted file mode 100644 index 43abe15..0000000 --- a/src/views/crm/receivable/plan/index.vue +++ /dev/null @@ -1,335 +0,0 @@ -<template> - <doc-alert title="銆愬洖娆俱�戝洖娆剧鐞嗐�佸洖娆捐鍒�" url="https://doc.iocoder.cn/crm/receivable/" /> - <doc-alert title="銆愰�氱敤銆戞暟鎹潈闄�" url="https://doc.iocoder.cn/crm/permission/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="瀹㈡埛鍚嶇О" prop="customerId"> - <el-select - v-model="queryParams.customerId" - class="!w-240px" - placeholder="璇烽�夋嫨瀹㈡埛" - @keyup.enter="handleQuery" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍚堝悓缂栧彿" prop="contractNo"> - <el-input - v-model="queryParams.contractNo" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ悎鍚岀紪鍙�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="activeName" @tab-click="handleTabClick"> - <el-tab-pane label="鎴戣礋璐g殑" name="1" /> - <el-tab-pane label="涓嬪睘璐熻矗鐨�" name="3" /> - </el-tabs> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="150"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" label="鍚堝悓缂栧彿" prop="contractNo" width="200px" /> - <el-table-column align="center" label="鏈熸暟" prop="period"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.period }} - </el-link> - </template> - </el-table-column> - <el-table-column - align="center" - label="璁″垝鍥炴閲戦锛堝厓锛�" - prop="price" - width="160" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - :formatter="dateFormatter2" - align="center" - label="璁″垝鍥炴鏃ユ湡" - prop="returnTime" - width="180px" - /> - <el-table-column align="center" label="鎻愬墠鍑犲ぉ鎻愰啋" prop="remindDays" width="150" /> - <el-table-column - align="center" - label="鎻愰啋鏃ユ湡" - prop="remindTime" - width="180px" - :formatter="dateFormatter2" - /> - <el-table-column align="center" label="鍥炴鏂瑰紡" prop="returnType" width="130px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE" :value="scope.row.returnType" /> - </template> - </el-table-column> - <el-table-column align="center" label="澶囨敞" prop="remark" /> - <el-table-column label="璐熻矗浜�" prop="ownerUserName" width="120" /> - <el-table-column - align="center" - label="瀹為檯鍥炴閲戦锛堝厓锛�" - prop="receivable.price" - width="160" - > - <template #default="scope"> - <el-text v-if="scope.row.receivable"> - {{ erpPriceInputFormatter(scope.row.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(0) }}</el-text> - </template> - </el-table-column> - <el-table-column - align="center" - label="瀹為檯鍥炴鏃ユ湡" - prop="receivable.returnTime" - width="180px" - :formatter="dateFormatter2" - /> - <el-table-column - align="center" - label="瀹為檯鍥炴閲戦锛堝厓锛�" - prop="receivable.price" - width="160" - > - <template #default="scope"> - <el-text v-if="scope.row.receivable"> - {{ erpPriceInputFormatter(scope.row.price - scope.row.receivable.price) }} - </el-text> - <el-text v-else>{{ erpPriceInputFormatter(scope.row.price) }}</el-text> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="180px"> - <template #default="scope"> - <el-button - v-hasPermi="['crm:receivable:create']" - link - type="success" - @click="openReceivableForm(scope.row)" - :disabled="scope.row.receivableId" - > - 鍒涘缓鍥炴 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['crm:receivable-plan:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ReceivablePlanForm ref="formRef" @success="getList" /> - <ReceivableForm ref="receivableFormRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter, dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import * as ReceivablePlanApi from '@/api/crm/receivable/plan' -import ReceivablePlanForm from './ReceivablePlanForm.vue' -import * as CustomerApi from '@/api/crm/customer' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { TabsPaneContext } from 'element-plus' -import ReceivableForm from '@/views/crm/receivable/ReceivableForm.vue' - -defineOptions({ name: 'ReceivablePlan' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - sceneType: '1', // 榛樿鍜� activeName 鐩哥瓑 - customerId: undefined, - contractNo: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const activeName = ref('1') // 鍒楄〃 tab -const customerList = ref<CustomerApi.CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 - -/** tab 鍒囨崲 */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.sceneType = tab.paneName - handleQuery() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ReceivablePlanApi.getReceivablePlanPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒涘缓鍥炴鎿嶄綔 */ -const receivableFormRef = ref() -const openReceivableForm = (row: ReceivablePlanApi.ReceivablePlanVO) => { - receivableFormRef.value.open('create', undefined, row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ReceivablePlanApi.deleteReceivablePlan(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ReceivablePlanApi.exportReceivablePlan(queryParams) - download.excel(data, '鍥炴璁″垝.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鎵撳紑璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmReceivablePlanDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerConversionStat.vue b/src/views/crm/statistics/customer/components/CustomerConversionStat.vue deleted file mode 100644 index 4f5c50c..0000000 --- a/src/views/crm/statistics/customer/components/CustomerConversionStat.vue +++ /dev/null @@ -1,170 +0,0 @@ -<!-- 瀹㈡埛杞寲鐜囧垎鏋� --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" fixed="left" /> - <el-table-column - label="瀹㈡埛鍚嶇О" - align="center" - prop="customerName" - min-width="200" - fixed="left" - /> - <el-table-column label="鍚堝悓鍚嶇О" align="center" prop="contractName" min-width="200" /> - <el-table-column - label="鍚堝悓鎬婚噾棰�" - align="center" - prop="totalPrice" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍥炴閲戦" - align="center" - prop="receivablePrice" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column label="璐熻矗浜�" align="center" prop="ownerUserName" min-width="200" /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorUserName" min-width="200" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - min-width="200" - /> - <el-table-column - label="涓嬪崟鏃ユ湡" - align="center" - prop="orderDate" - :formatter="dateFormatter" - min-width="200" - fixed="right" - /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsCustomerSummaryByDateRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' -import { dateFormatter } from '@/utils/formatTime' -import { erpPriceTableColumnFormatter } from '@/utils' -import { DICT_TYPE } from '@/utils/dict' - -defineOptions({ name: 'CustomerConversionStat' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsCustomerSummaryByDateRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 40, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '瀹㈡埛杞寲鐜�', - type: 'line', - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛杞寲鐜囧垎鏋�' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: { - type: 'value', - name: '杞寲鐜�(%)' - }, - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const customerCount = await StatisticsCustomerApi.getCustomerSummaryByDate(props.queryParams) - const contractSummary = await StatisticsCustomerApi.getContractSummary(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = customerCount.map( - (s: CrmStatisticsCustomerSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = customerCount.map( - (item: CrmStatisticsCustomerSummaryByDateRespVO) => { - return { - name: item.time, - value: item.customerCreateCount - ? ((item.customerDealCount / item.customerCreateCount) * 100).toFixed(2) - : 0 - } - } - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = contractSummary -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerDealCycleByArea.vue b/src/views/crm/statistics/customer/components/CustomerDealCycleByArea.vue deleted file mode 100644 index 9aa6d5e..0000000 --- a/src/views/crm/statistics/customer/components/CustomerDealCycleByArea.vue +++ /dev/null @@ -1,153 +0,0 @@ -<!-- 鎴愪氦鍛ㄦ湡鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" /> - <el-table-column label="鍖哄煙" align="center" prop="areaName" min-width="200" /> - <el-table-column - label="鎴愪氦鍛ㄦ湡(澶�)" - align="center" - prop="customerDealCycle" - min-width="200" - /> - <el-table-column label="鎴愪氦瀹㈡埛鏁�" align="center" prop="customerDealCount" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsCustomerDealCycleByAreaRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' - -defineOptions({ name: 'CustomerDealCycleByArea' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsCustomerDealCycleByAreaRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 40, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '鎴愪氦鍛ㄦ湡(澶�)', - type: 'bar', - data: [], - yAxisIndex: 0 - }, - { - name: '鎴愪氦瀹㈡埛鏁�', - type: 'bar', - data: [], - yAxisIndex: 1 - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鎴愪氦鍛ㄦ湡鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鎴愪氦鍛ㄦ湡(澶�)', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鎴愪氦瀹㈡埛鏁�', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鍖哄煙', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const customerDealCycleByArea = ( - await StatisticsCustomerApi.getCustomerDealCycleByArea(props.queryParams) - ).map((s: CrmStatisticsCustomerDealCycleByAreaRespVO) => { - return { - areaName: s.areaName, - customerDealCycle: s.customerDealCycle, - customerDealCount: s.customerDealCount - } - }) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = customerDealCycleByArea.map( - (s: CrmStatisticsCustomerDealCycleByAreaRespVO) => s.areaName - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = customerDealCycleByArea.map( - (s: CrmStatisticsCustomerDealCycleByAreaRespVO) => s.customerDealCycle - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = customerDealCycleByArea.map( - (s: CrmStatisticsCustomerDealCycleByAreaRespVO) => s.customerDealCount - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = customerDealCycleByArea -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerDealCycleByProduct.vue b/src/views/crm/statistics/customer/components/CustomerDealCycleByProduct.vue deleted file mode 100644 index 74558d1..0000000 --- a/src/views/crm/statistics/customer/components/CustomerDealCycleByProduct.vue +++ /dev/null @@ -1,153 +0,0 @@ -<!-- 鎴愪氦鍛ㄦ湡鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" /> - <el-table-column label="浜у搧鍚嶇О" align="center" prop="productName" min-width="200" /> - <el-table-column - label="鎴愪氦鍛ㄦ湡(澶�)" - align="center" - prop="customerDealCycle" - min-width="200" - /> - <el-table-column label="鎴愪氦瀹㈡埛鏁�" align="center" prop="customerDealCount" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsCustomerDealCycleByProductRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' - -defineOptions({ name: 'CustomerDealCycleByProduct' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsCustomerDealCycleByProductRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 40, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '鎴愪氦鍛ㄦ湡(澶�)', - type: 'bar', - data: [], - yAxisIndex: 0 - }, - { - name: '鎴愪氦瀹㈡埛鏁�', - type: 'bar', - data: [], - yAxisIndex: 1 - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鎴愪氦鍛ㄦ湡鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鎴愪氦鍛ㄦ湡(澶�)', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鎴愪氦瀹㈡埛鏁�', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '浜у搧鍚嶇О', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const customerDealCycleByProduct = ( - await StatisticsCustomerApi.getCustomerDealCycleByProduct(props.queryParams) - ).map((s: CrmStatisticsCustomerDealCycleByProductRespVO) => { - return { - productName: s.productName ?? '鏈煡', - customerDealCycle: s.customerDealCount, - customerDealCount: s.customerDealCount - } - }) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = customerDealCycleByProduct.map( - (s: CrmStatisticsCustomerDealCycleByProductRespVO) => s.productName - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = customerDealCycleByProduct.map( - (s: CrmStatisticsCustomerDealCycleByProductRespVO) => s.customerDealCycle - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = customerDealCycleByProduct.map( - (s: CrmStatisticsCustomerDealCycleByProductRespVO) => s.customerDealCount - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = customerDealCycleByProduct -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerDealCycleByUser.vue b/src/views/crm/statistics/customer/components/CustomerDealCycleByUser.vue deleted file mode 100644 index e3d877e..0000000 --- a/src/views/crm/statistics/customer/components/CustomerDealCycleByUser.vue +++ /dev/null @@ -1,154 +0,0 @@ -<!-- 鎴愪氦鍛ㄦ湡鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" /> - <el-table-column label="鏃ユ湡" align="center" prop="ownerUserName" min-width="200" /> - <el-table-column - label="鎴愪氦鍛ㄦ湡(澶�)" - align="center" - prop="customerDealCycle" - min-width="200" - /> - <el-table-column label="鎴愪氦瀹㈡埛鏁�" align="center" prop="customerDealCount" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsCustomerDealCycleByDateRespVO, - CrmStatisticsCustomerSummaryByDateRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' - -defineOptions({ name: 'CustomerDealCycleByUser' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsCustomerDealCycleByDateRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 40, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '鎴愪氦鍛ㄦ湡(澶�)', - type: 'bar', - data: [], - yAxisIndex: 0 - }, - { - name: '鎴愪氦瀹㈡埛鏁�', - type: 'bar', - data: [], - yAxisIndex: 1 - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鎴愪氦鍛ㄦ湡鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鎴愪氦鍛ㄦ湡(澶�)', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鎴愪氦瀹㈡埛鏁�', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const customerDealCycleByDate = await StatisticsCustomerApi.getCustomerDealCycleByDate( - props.queryParams - ) - const customerSummaryByDate = await StatisticsCustomerApi.getCustomerSummaryByDate( - props.queryParams - ) - const customerDealCycleByUser = await StatisticsCustomerApi.getCustomerDealCycleByUser( - props.queryParams - ) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = customerDealCycleByDate.map( - (s: CrmStatisticsCustomerDealCycleByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = customerDealCycleByDate.map( - (s: CrmStatisticsCustomerDealCycleByDateRespVO) => s.customerDealCycle - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = customerSummaryByDate.map( - (s: CrmStatisticsCustomerSummaryByDateRespVO) => s.customerDealCount - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = customerDealCycleByUser -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerFollowUpSummary.vue b/src/views/crm/statistics/customer/components/CustomerFollowUpSummary.vue deleted file mode 100644 index eeb0ff0..0000000 --- a/src/views/crm/statistics/customer/components/CustomerFollowUpSummary.vue +++ /dev/null @@ -1,156 +0,0 @@ -<!-- 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" /> - <el-table-column label="鍛樺伐濮撳悕" align="center" prop="ownerUserName" min-width="200" /> - <el-table-column label="璺熻繘娆℃暟" align="right" prop="followUpRecordCount" min-width="200" /> - <el-table-column - label="璺熻繘瀹㈡埛鏁�" - align="right" - prop="followUpCustomerCount" - min-width="200" - /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsFollowUpSummaryByDateRespVO, - CrmStatisticsFollowUpSummaryByUserRespVO -} from '@/api/crm/statistics/customer' -import Echart from '@/components/Echart/src/Echart.vue' -import { EChartsOption } from 'echarts' - -defineOptions({ name: 'CustomerFollowupSummary' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsFollowUpSummaryByUserRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 30, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '璺熻繘瀹㈡埛鏁�', - type: 'bar', - yAxisIndex: 0, - data: [] - }, - { - name: '璺熻繘娆℃暟', - type: 'bar', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛璺熻繘娆℃暟鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '璺熻繘瀹㈡埛鏁�', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '璺熻繘娆℃暟', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - axisTick: { - alignWithLabel: true - }, - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const followUpSummaryByDate = await StatisticsCustomerApi.getFollowUpSummaryByDate( - props.queryParams - ) - const followUpSummaryByUser = await StatisticsCustomerApi.getFollowUpSummaryByUser( - props.queryParams - ) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = followUpSummaryByDate.map( - (s: CrmStatisticsFollowUpSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = followUpSummaryByDate.map( - (s: CrmStatisticsFollowUpSummaryByDateRespVO) => s.followUpCustomerCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = followUpSummaryByDate.map( - (s: CrmStatisticsFollowUpSummaryByDateRespVO) => s.followUpRecordCount - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = followUpSummaryByUser -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerFollowUpType.vue b/src/views/crm/statistics/customer/components/CustomerFollowUpType.vue deleted file mode 100644 index 3d8d873..0000000 --- a/src/views/crm/statistics/customer/components/CustomerFollowUpType.vue +++ /dev/null @@ -1,120 +0,0 @@ -<!-- 瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" /> - <el-table-column label="璺熻繘鏂瑰紡" align="center" prop="followUpType" min-width="200"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_FOLLOW_UP_TYPE" :value="scope.row.followUpType" /> - </template> - </el-table-column> - <el-table-column label="涓暟" align="center" prop="followUpRecordCount" min-width="200" /> - <el-table-column label="鍗犳瘮(%)" align="center" prop="portion" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsFollowUpSummaryByTypeRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' -import { sumBy } from 'lodash-es' -import { DICT_TYPE, getDictLabel } from '@/utils/dict' -import { erpCalculatePercentage } from '@/utils' - -defineOptions({ name: 'CustomerFollowupType' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsFollowUpSummaryByTypeRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 楗煎浘閰嶇疆 */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽', - left: 'center' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - tooltip: { - trigger: 'item', - formatter: '{b} : {c}% ' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '璺熻繘鏂瑰紡', - type: 'pie', - radius: '50%', - data: [], - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - } - } - } - ] -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const followUpSummaryByType = await StatisticsCustomerApi.getFollowUpSummaryByType( - props.queryParams - ) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = followUpSummaryByType.map( - (row: CrmStatisticsFollowUpSummaryByTypeRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_FOLLOW_UP_TYPE, row.followUpType), - value: row.followUpRecordCount - } - } - ) - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - const totalCount = sumBy(followUpSummaryByType, 'followUpRecordCount') - list.value = followUpSummaryByType.map((row: CrmStatisticsFollowUpSummaryByTypeRespVO) => { - return { - ...row, - portion: erpCalculatePercentage(row.followUpRecordCount, totalCount) - } - }) -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerPoolSummary.vue b/src/views/crm/statistics/customer/components/CustomerPoolSummary.vue deleted file mode 100644 index 5f0606a..0000000 --- a/src/views/crm/statistics/customer/components/CustomerPoolSummary.vue +++ /dev/null @@ -1,154 +0,0 @@ -<!-- 瀹㈡埛鎬婚噺缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" fixed="left" /> - <el-table-column label="鍛樺伐濮撳悕" prop="ownerUserName" min-width="100" fixed="left" /> - <el-table-column - label="杩涘叆鍏捣瀹㈡埛鏁�" - align="right" - prop="customerPutCount" - min-width="200" - /> - <el-table-column - label="鍏捣棰嗗彇瀹㈡埛鏁�" - align="right" - prop="customerTakeCount" - min-width="200" - /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsPoolSummaryByDateRespVO, - CrmStatisticsPoolSummaryByUserRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' - -defineOptions({ name: 'CustomerPoolSummary' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsPoolSummaryByUserRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 40, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '杩涘叆鍏捣瀹㈡埛鏁�', - type: 'bar', - yAxisIndex: 0, - data: [] - }, - { - name: '鍏捣棰嗗彇瀹㈡埛鏁�', - type: 'bar', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鍏捣瀹㈡埛鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '杩涘叆鍏捣瀹㈡埛鏁�', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鍏捣棰嗗彇瀹㈡埛鏁�', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const poolSummaryByDate = await StatisticsCustomerApi.getPoolSummaryByDate(props.queryParams) - const poolSummaryByUser = await StatisticsCustomerApi.getPoolSummaryByUser(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = poolSummaryByDate.map( - (s: CrmStatisticsPoolSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = poolSummaryByDate.map( - (s: CrmStatisticsPoolSummaryByDateRespVO) => s.customerPutCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = poolSummaryByDate.map( - (s: CrmStatisticsPoolSummaryByDateRespVO) => s.customerTakeCount - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = poolSummaryByUser -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/components/CustomerSummary.vue b/src/views/crm/statistics/customer/components/CustomerSummary.vue deleted file mode 100644 index d1429c2..0000000 --- a/src/views/crm/statistics/customer/components/CustomerSummary.vue +++ /dev/null @@ -1,183 +0,0 @@ -<!-- 瀹㈡埛鎬婚噺缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴忓彿" align="center" type="index" width="80" fixed="left" /> - <el-table-column label="鍛樺伐濮撳悕" prop="ownerUserName" min-width="100" fixed="left" /> - <el-table-column - label="鏂板瀹㈡埛鏁�" - align="right" - prop="customerCreateCount" - min-width="200" - /> - <el-table-column label="鎴愪氦瀹㈡埛鏁�" align="right" prop="customerDealCount" min-width="200" /> - <el-table-column label="瀹㈡埛鎴愪氦鐜�(%)" align="right" min-width="200"> - <template #default="scope"> - {{ erpCalculatePercentage(scope.row.customerDealCount, scope.row.customerCreateCount) }} - </template> - </el-table-column> - <el-table-column - label="鍚堝悓鎬婚噾棰�" - align="right" - prop="contractPrice" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍥炴閲戦" - align="right" - prop="receivablePrice" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈洖娆鹃噾棰�" align="right" min-width="200"> - <template #default="scope"> - {{ erpCalculatePercentage(scope.row.receivablePrice, scope.row.contractPrice) }} - </template> - </el-table-column> - <el-table-column label="鍥炴瀹屾垚鐜�(%)" align="right" min-width="200" fixed="right"> - <template #default="scope"> - {{ erpCalculatePercentage(scope.row.receivablePrice, scope.row.contractPrice) }} - </template> - </el-table-column> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { - StatisticsCustomerApi, - CrmStatisticsCustomerSummaryByDateRespVO, - CrmStatisticsCustomerSummaryByUserRespVO -} from '@/api/crm/statistics/customer' -import { EChartsOption } from 'echarts' -import { erpCalculatePercentage, erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'CustomerSummary' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticsCustomerSummaryByUserRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 30, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '鏂板瀹㈡埛鏁�', - type: 'bar', - yAxisIndex: 0, - data: [] - }, - { - name: '鎴愪氦瀹㈡埛鏁�', - type: 'bar', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛鎬婚噺鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鏂板瀹㈡埛鏁�', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鎴愪氦瀹㈡埛鏁�', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const customerSummaryByDate = await StatisticsCustomerApi.getCustomerSummaryByDate( - props.queryParams - ) - const customerSummaryByUser = await StatisticsCustomerApi.getCustomerSummaryByUser( - props.queryParams - ) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = customerSummaryByDate.map( - (s: CrmStatisticsCustomerSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = customerSummaryByDate.map( - (s: CrmStatisticsCustomerSummaryByDateRespVO) => s.customerCreateCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = customerSummaryByDate.map( - (s: CrmStatisticsCustomerSummaryByDateRespVO) => s.customerDealCount - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = customerSummaryByUser -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/customer/index.vue b/src/views/crm/statistics/customer/index.vue deleted file mode 100644 index 207dc35..0000000 --- a/src/views/crm/statistics/customer/index.vue +++ /dev/null @@ -1,214 +0,0 @@ -<!-- 鏁版嵁缁熻 - 鍛樺伐瀹㈡埛鍒嗘瀽 --> -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鏃堕棿鑼冨洿" prop="orderDate"> - <el-date-picker - v-model="queryParams.times" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - :shortcuts="defaultShortcuts" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - @change="handleQuery" - /> - </el-form-item> - <el-form-item label="鏃堕棿闂撮殧" prop="interval"> - <el-select - v-model="queryParams.interval" - class="!w-240px" - placeholder="闂撮殧绫诲瀷" - @change="handleQuery" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.DATE_INTERVAL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId"> - <el-tree-select - v-model="queryParams.deptId" - :data="deptList" - :props="defaultProps" - check-strictly - class="!w-240px" - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - @change="(queryParams.userId = undefined), handleQuery()" - /> - </el-form-item> - <el-form-item label="鍛樺伐" prop="userId"> - <el-select - v-model="queryParams.userId" - class="!w-240px" - clearable - placeholder="鍛樺伐" - @change="handleQuery" - > - <el-option - v-for="(user, index) in userListByDeptId" - :key="index" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鏌ヨ - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 瀹㈡埛缁熻 --> - <el-col> - <el-tabs v-model="activeTab"> - <!-- 瀹㈡埛鎬婚噺鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛鎬婚噺鍒嗘瀽" lazy name="customerSummary"> - <CustomerSummary ref="customerSummaryRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛璺熻繘娆℃暟鍒嗘瀽" lazy name="followUpSummary"> - <CustomerFollowUpSummary ref="followUpSummaryRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽" lazy name="followUpType"> - <CustomerFollowUpType ref="followUpTypeRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛杞寲鐜囧垎鏋� --> - <el-tab-pane label="瀹㈡埛杞寲鐜囧垎鏋�" lazy name="conversionStat"> - <CustomerConversionStat ref="conversionStatRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 鍏捣瀹㈡埛鍒嗘瀽 --> - <el-tab-pane label="鍏捣瀹㈡埛鍒嗘瀽" lazy name="poolSummary"> - <CustomerPoolSummary ref="customerPoolSummaryRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 鎴愪氦鍛ㄦ湡鍒嗘瀽 --> - <el-tab-pane label="鍛樺伐瀹㈡埛鎴愪氦鍛ㄦ湡鍒嗘瀽" lazy name="dealCycleByUser"> - <CustomerDealCycleByUser ref="dealCycleByUserRef" :query-params="queryParams" /> - </el-tab-pane> - <el-tab-pane label="鍦板尯瀹㈡埛鎴愪氦鍛ㄦ湡鍒嗘瀽" lazy name="dealCycleByArea"> - <CustomerDealCycleByArea ref="dealCycleByAreaRef" :query-params="queryParams" /> - </el-tab-pane> - <el-tab-pane label="浜у搧瀹㈡埛鎴愪氦鍛ㄦ湡鍒嗘瀽" lazy name="dealCycleByProduct"> - <CustomerDealCycleByProduct ref="dealCycleByProductRef" :query-params="queryParams" /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> - -<script lang="ts" setup> -import * as DeptApi from '@/api/system/dept' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime' -import { defaultProps, handleTree } from '@/utils/tree' -import CustomerConversionStat from './components/CustomerConversionStat.vue' -import CustomerDealCycleByUser from './components/CustomerDealCycleByUser.vue' -import CustomerDealCycleByArea from './components/CustomerDealCycleByArea.vue' -import CustomerDealCycleByProduct from './components/CustomerDealCycleByProduct.vue' -import CustomerFollowUpSummary from './components/CustomerFollowUpSummary.vue' -import CustomerFollowUpType from './components/CustomerFollowUpType.vue' -import CustomerSummary from './components/CustomerSummary.vue' -import CustomerPoolSummary from './components/CustomerPoolSummary.vue' - -defineOptions({ name: 'CrmStatisticsCustomer' }) - -const queryParams = reactive({ - interval: 2, // WEEK, 鍛� - deptId: useUserStore().getUser.deptId, - userId: undefined, - times: [ - // 榛樿鏄剧ず鏈�杩戜竴鍛ㄧ殑鏁版嵁 - formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))), - formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))) - ] -}) - -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const deptList = ref<Tree[]>([]) // 閮ㄩ棬鏍戝舰缁撴瀯 -const userList = ref<UserApi.UserVO[]>([]) // 鍏ㄩ噺鐢ㄦ埛娓呭崟 - -/** 鏍规嵁閫夋嫨鐨勯儴闂ㄧ瓫閫夊憳宸ユ竻鍗� */ -const userListByDeptId = computed(() => - queryParams.deptId - ? userList.value.filter((u: UserApi.UserVO) => u.deptId === queryParams.deptId) - : [] -) - -const activeTab = ref('customerSummary') // 娲昏穬鏍囩 -const customerSummaryRef = ref() // 1. 瀹㈡埛鎬婚噺鍒嗘瀽 -const followUpSummaryRef = ref() // 2. 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽 -const followUpTypeRef = ref() // 3. 瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽 -const conversionStatRef = ref() // 4. 瀹㈡埛杞寲鐜囧垎鏋� -const customerPoolSummaryRef = ref() // 5. 瀹㈡埛鍏捣鍒嗘瀽 -const dealCycleByUserRef = ref() // 6. 鎴愪氦鍛ㄦ湡鍒嗘瀽(鎸夊憳宸�) -const dealCycleByAreaRef = ref() // 7. 鎴愪氦鍛ㄦ湡鍒嗘瀽(鎸夊湴鍖�) -const dealCycleByProductRef = ref() // 8. 鎴愪氦鍛ㄦ湡鍒嗘瀽(鎸変骇鍝�) - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - switch (activeTab.value) { - case 'customerSummary': // 瀹㈡埛鎬婚噺鍒嗘瀽 - customerSummaryRef.value?.loadData?.() - break - case 'followUpSummary': // 瀹㈡埛璺熻繘娆℃暟鍒嗘瀽 - followUpSummaryRef.value?.loadData?.() - break - case 'followUpType': // 瀹㈡埛璺熻繘鏂瑰紡鍒嗘瀽 - followUpTypeRef.value?.loadData?.() - break - case 'conversionStat': // 瀹㈡埛杞寲鐜囧垎鏋� - conversionStatRef.value?.loadData?.() - break - case 'poolSummary': // 鍏捣瀹㈡埛鍒嗘瀽 - customerPoolSummaryRef.value?.loadData?.() - break - case 'dealCycleByUser': // 鎴愪氦鍛ㄦ湡鍒嗘瀽 - dealCycleByUserRef.value?.loadData?.() - break - case 'dealCycleByArea': // 鎴愪氦鍛ㄦ湡鍒嗘瀽 - dealCycleByAreaRef.value?.loadData?.() - break - case 'dealCycleByProduct': // 鎴愪氦鍛ㄦ湡鍒嗘瀽 - dealCycleByProductRef.value?.loadData?.() - break - } -} - -/** 褰� activeTab 鏀瑰彉鏃讹紝鍒锋柊褰撳墠娲诲姩鐨� tab */ -watch(activeTab, () => { - handleQuery() -}) - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� */ -onMounted(async () => { - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) - userList.value = handleTree(await UserApi.getSimpleUserList()) -}) -</script> diff --git a/src/views/crm/statistics/funnel/components/BusinessInversionRateSummary.vue b/src/views/crm/statistics/funnel/components/BusinessInversionRateSummary.vue deleted file mode 100644 index 541d6fc..0000000 --- a/src/views/crm/statistics/funnel/components/BusinessInversionRateSummary.vue +++ /dev/null @@ -1,307 +0,0 @@ -<!-- 瀹㈡埛鎬婚噺缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" fixed="left" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" fixed="left" label="鍟嗘満鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column - :formatter="erpPriceTableColumnFormatter" - align="center" - label="鍟嗘満閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="棰勮鎴愪氦鏃ユ湡" - prop="dealTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満鐘舵�佺粍" - prop="statusTypeName" - width="140" - /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満闃舵" - prop="statusName" - width="120" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams0.pageSize" - v-model:page="queryParams0.pageNo" - :total="total" - @pagination="getList" - /> - </el-card> -</template> -<script lang="ts" setup> -import { - CrmStatisticsBusinessInversionRateSummaryByDateRespVO, - StatisticFunnelApi -} from '@/api/crm/statistics/funnel' -import { EChartsOption } from 'echarts' -import { erpCalculatePercentage, erpPriceTableColumnFormatter } from '@/utils' -import { dateFormatter } from '@/utils/formatTime' - -defineOptions({ name: 'BusinessSummary' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 -const queryParams0 = reactive({ - pageNo: 1, - pageSize: 10 -}) -const loading = ref(false) // 鍔犺浇涓� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 queryParams0 */ -watch( - () => props.queryParams, - (data) => { - if (!data) { - return - } - const newObj = { ...queryParams0, ...data } - Object.assign(queryParams0, newObj) - }, - { - immediate: true - } -) -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - color: ['#6ca2ff', '#6ac9d7', '#ff7474'], - tooltip: { - trigger: 'axis', - axisPointer: { - // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥 - type: 'shadow' // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow' - } - }, - legend: { - data: ['璧㈠崟杞寲鐜�', '鍟嗘満鎬绘暟', '璧㈠崟鍟嗘満鏁�'], - bottom: '0px', - itemWidth: 14 - }, - grid: { - top: '40px', - left: '40px', - right: '40px', - bottom: '40px', - containLabel: true, - borderColor: '#fff' - }, - xAxis: [ - { - type: 'category', - data: [], - axisTick: { - alignWithLabel: true, - lineStyle: { width: 0 } - }, - axisLabel: { - color: '#BDBDBD' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { color: '#BDBDBD' } - }, - splitLine: { - show: false - } - } - ], - yAxis: [ - { - type: 'value', - name: '璧㈠崟杞寲鐜�', - axisTick: { - alignWithLabel: true, - lineStyle: { width: 0 } - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}%' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { color: '#BDBDBD' } - }, - splitLine: { - show: false - } - }, - { - type: 'value', - name: '鍟嗘満鏁�', - axisTick: { - alignWithLabel: true, - lineStyle: { width: 0 } - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}涓�' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { color: '#BDBDBD' } - }, - splitLine: { - show: false - } - } - ], - series: [ - { - name: '璧㈠崟杞寲鐜�', - type: 'line', - yAxisIndex: 0, - data: [] - }, - { - name: '鍟嗘満鎬绘暟', - type: 'bar', - yAxisIndex: 1, - barWidth: 15, - data: [] - }, - { - name: '璧㈠崟鍟嗘満鏁�', - type: 'bar', - yAxisIndex: 1, - barWidth: 15, - data: [] - } - ] -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const businessSummaryByDate = await StatisticFunnelApi.getBusinessInversionRateSummaryByDate( - props.queryParams - ) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis[0] && echartsOption.xAxis[0]['data']) { - echartsOption.xAxis[0]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessInversionRateSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessInversionRateSummaryByDateRespVO) => - erpCalculatePercentage(s.businessWinCount, s.businessCount) - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessInversionRateSummaryByDateRespVO) => s.businessCount - ) - } - if (echartsOption.series && echartsOption.series[2] && echartsOption.series[2]['data']) { - echartsOption.series[2]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessInversionRateSummaryByDateRespVO) => s.businessWinCount - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - await getList() -} -/** 鑾峰彇鍟嗘満鍒楄〃 */ -const getList = async () => { - const data = await StatisticFunnelApi.getBusinessPageByDate(props.queryParams) - list.value = data.list - total.value = data.total -} -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/funnel/components/BusinessSummary.vue b/src/views/crm/statistics/funnel/components/BusinessSummary.vue deleted file mode 100644 index 942a712..0000000 --- a/src/views/crm/statistics/funnel/components/BusinessSummary.vue +++ /dev/null @@ -1,259 +0,0 @@ -<!-- 瀹㈡埛鎬婚噺缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" fixed="left" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" fixed="left" label="鍟嗘満鍚嶇О" prop="name" width="160"> - <template #default="scope"> - <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> - {{ scope.row.name }} - </el-link> - </template> - </el-table-column> - <el-table-column align="center" fixed="left" label="瀹㈡埛鍚嶇О" prop="customerName" width="120"> - <template #default="scope"> - <el-link - :underline="false" - type="primary" - @click="openCustomerDetail(scope.row.customerId)" - > - {{ scope.row.customerName }} - </el-link> - </template> - </el-table-column> - <el-table-column - :formatter="erpPriceTableColumnFormatter" - align="center" - label="鍟嗘満閲戦锛堝厓锛�" - prop="totalPrice" - width="140" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="棰勮鎴愪氦鏃ユ湡" - prop="dealTime" - width="180px" - /> - <el-table-column align="center" label="澶囨敞" prop="remark" width="200" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="涓嬫鑱旂郴鏃堕棿" - prop="contactNextTime" - width="180px" - /> - <el-table-column align="center" label="璐熻矗浜�" prop="ownerUserName" width="100px" /> - <el-table-column align="center" label="鎵�灞為儴闂�" prop="ownerUserDeptName" width="100px" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏈�鍚庤窡杩涙椂闂�" - prop="contactLastTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏇存柊鏃堕棿" - prop="updateTime" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鍒涘缓浜�" prop="creatorName" width="100px" /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満鐘舵�佺粍" - prop="statusTypeName" - width="140" - /> - <el-table-column - align="center" - fixed="right" - label="鍟嗘満闃舵" - prop="statusName" - width="120" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams0.pageSize" - v-model:page="queryParams0.pageNo" - :total="total" - @pagination="getList" - /> - </el-card> -</template> -<script lang="ts" setup> -import { - CrmStatisticsBusinessSummaryByDateRespVO, - StatisticFunnelApi -} from '@/api/crm/statistics/funnel' -import { EChartsOption } from 'echarts' -import { erpPriceTableColumnFormatter } from '@/utils' -import { dateFormatter } from '@/utils/formatTime' - -defineOptions({ name: 'BusinessSummary' }) - -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 -const queryParams0 = reactive({ - pageNo: 1, - pageSize: 10 -}) -const loading = ref(false) // 鍔犺浇涓� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 queryParams0 */ -watch( - () => props.queryParams, - (data) => { - if (!data) { - return - } - const newObj = { ...queryParams0, ...data } - Object.assign(queryParams0, newObj) - }, - { - immediate: true - } -) -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 30, - right: 30, // 璁� X 杞村彸渚ф樉绀哄畬鏁� - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '鏂板鍟嗘満鏁伴噺', - type: 'bar', - yAxisIndex: 0, - data: [] - }, - { - name: '鏂板鍟嗘満閲戦', - type: 'bar', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鏂板鍟嗘満鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鏂板鍟嗘満鏁伴噺', - min: 0, - minInterval: 1 // 鏄剧ず鏁存暟鍒诲害 - }, - { - type: 'value', - name: '鏂板鍟嗘満閲戦', - min: 0, - minInterval: 1, // 鏄剧ず鏁存暟鍒诲害 - splitLine: { - lineStyle: { - type: 'dotted', // 鍙充晶缃戞牸绾胯櫄鍖�, 鍑忓皯娣蜂贡 - opacity: 0.7 - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇鏁版嵁骞跺~鍏呭浘琛� */ -const fetchAndFill = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - const businessSummaryByDate = await StatisticFunnelApi.getBusinessSummaryByDate(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessSummaryByDateRespVO) => s.time - ) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessSummaryByDateRespVO) => s.businessCreateCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = businessSummaryByDate.map( - (s: CrmStatisticsBusinessSummaryByDateRespVO) => s.totalPrice - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - await getList() -} -/** 鑾峰彇鍟嗘満鍒楄〃 */ -const getList = async () => { - const data = await StatisticFunnelApi.getBusinessPageByDate(props.queryParams) - list.value = data.list - total.value = data.total -} -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'CrmBusinessDetail', params: { id } }) -} - -/** 鎵撳紑瀹㈡埛璇︽儏 */ -const openCustomerDetail = (id: number) => { - push({ name: 'CrmCustomerDetail', params: { id } }) -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - try { - await fetchAndFill() - } finally { - loading.value = false - } -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/funnel/components/FunnelBusiness.vue b/src/views/crm/statistics/funnel/components/FunnelBusiness.vue deleted file mode 100644 index c4e4bf6..0000000 --- a/src/views/crm/statistics/funnel/components/FunnelBusiness.vue +++ /dev/null @@ -1,149 +0,0 @@ -<!-- 閿�鍞紡鏂楀垎鏋� --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-row> - <el-col :span="24"> - <el-button-group class="mb-10px"> - <el-button type="primary" @click="handleActive(true)">瀹㈡埛瑙嗚</el-button> - <el-button type="primary" @click="handleActive(false)">鍔ㄦ�佽瑙�</el-button> - </el-button-group> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-col> - </el-row> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" label="闃舵" prop="endStatus" width="200"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_BUSINESS_END_STATUS_TYPE" :value="scope.row.endStatus" /> - </template> - </el-table-column> - <el-table-column align="center" label="鍟嗘満鏁�" min-width="200" prop="businessCount" /> - <el-table-column align="center" label="鍟嗘満鎬婚噾棰�(鍏�)" min-width="200" prop="totalPrice" /> - </el-table> - </el-card> -</template> -<script lang="ts" setup> -import { CrmStatisticFunnelRespVO, StatisticFunnelApi } from '@/api/crm/statistics/funnel' -import { EChartsOption } from 'echarts' -import { DICT_TYPE } from '@/utils/dict' - -defineOptions({ name: 'FunnelBusiness' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const active = ref(true) -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticFunnelRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 閿�鍞紡鏂� */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '閿�鍞紡鏂�' - }, - tooltip: { - trigger: 'item', - formatter: '{a} <br/>{b}' - }, - toolbox: { - feature: { - dataView: { readOnly: false }, - restore: {}, - saveAsImage: {} - } - }, - legend: { - data: ['瀹㈡埛', '鍟嗘満', '璧㈠崟'] - }, - series: [ - { - name: '閿�鍞紡鏂�', - type: 'funnel', - left: '10%', - top: 60, - bottom: 60, - width: '80%', - min: 0, - max: 100, - minSize: '0%', - maxSize: '100%', - sort: 'descending', - gap: 2, - label: { - show: true, - position: 'inside' - }, - labelLine: { - length: 10, - lineStyle: { - width: 1, - type: 'solid' - } - }, - itemStyle: { - borderColor: '#fff', - borderWidth: 1 - }, - emphasis: { - label: { - fontSize: 20 - } - }, - data: [ - { value: 60, name: '瀹㈡埛-0涓�' }, - { value: 40, name: '鍟嗘満-0涓�' }, - { value: 20, name: '璧㈠崟-0涓�' } - ] - } - ] -}) as EChartsOption - -const handleActive = async (val: boolean) => { - active.value = val - await loadData() -} - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - loading.value = true - // 1. 鍔犺浇婕忔枟鏁版嵁 - const data = (await StatisticFunnelApi.getFunnelSummary( - props.queryParams - )) as CrmStatisticFunnelRespVO - // 2.1 鏇存柊 Echarts 鏁版嵁 - if ( - !!data && - echartsOption.series && - echartsOption.series[0] && - echartsOption.series[0]['data'] - ) { - // tips锛氬啓姝� value 鍊兼槸涓轰簡淇濇寔婕忔枟椤哄簭涓嶅彉 - const list: { value: number; name: string }[] = [] - if (active.value) { - list.push({ value: 60, name: `瀹㈡埛-${data.customerCount || 0}涓猔 }) - list.push({ value: 40, name: `鍟嗘満-${data.businessCount || 0}涓猔 }) - list.push({ value: 20, name: `璧㈠崟-${data.businessWinCount || 0}涓猔 }) - } else { - list.push({ value: data.customerCount || 0, name: `瀹㈡埛-${data.customerCount || 0}涓猔 }) - list.push({ value: data.businessCount || 0, name: `鍟嗘満-${data.businessCount || 0}涓猔 }) - list.push({ value: data.businessWinCount || 0, name: `璧㈠崟-${data.businessWinCount || 0}涓猔 }) - } - - echartsOption.series[0]['data'] = list - } - // 2.2 鑾峰彇鍟嗘満缁撴潫鐘舵�佺粺璁� - list.value = await StatisticFunnelApi.getBusinessSummaryByEndStatus(props.queryParams) - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/funnel/index.vue b/src/views/crm/statistics/funnel/index.vue deleted file mode 100644 index 804cb49..0000000 --- a/src/views/crm/statistics/funnel/index.vue +++ /dev/null @@ -1,171 +0,0 @@ -<!-- 鏁版嵁缁熻 - 瀹㈡埛鐢诲儚 --> -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鏃堕棿鑼冨洿" prop="orderDate"> - <el-date-picker - v-model="queryParams.times" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - :shortcuts="defaultShortcuts" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - @change="handleQuery" - /> - </el-form-item> - <el-form-item label="鏃堕棿闂撮殧" prop="interval"> - <el-select - v-model="queryParams.interval" - class="!w-240px" - placeholder="闂撮殧绫诲瀷" - @change="handleQuery" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.DATE_INTERVAL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId"> - <el-tree-select - v-model="queryParams.deptId" - :data="deptList" - :props="defaultProps" - check-strictly - class="!w-240px" - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - @change="(queryParams.userId = undefined), handleQuery()" - /> - </el-form-item> - <el-form-item label="鍛樺伐" prop="userId"> - <el-select - v-model="queryParams.userId" - class="!w-240px" - clearable - placeholder="鍛樺伐" - @change="handleQuery" - > - <el-option - v-for="(user, index) in userListByDeptId" - :key="index" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鏌ヨ - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 瀹㈡埛缁熻 --> - <el-col> - <el-tabs v-model="activeTab"> - <el-tab-pane label="閿�鍞紡鏂楀垎鏋�" lazy name="funnelRef"> - <FunnelBusiness ref="funnelRef" :query-params="queryParams" /> - </el-tab-pane> - <el-tab-pane label="鏂板鍟嗘満鍒嗘瀽" lazy name="businessSummaryRef"> - <BusinessSummary ref="businessSummaryRef" :query-params="queryParams" /> - </el-tab-pane> - <el-tab-pane label="鍟嗘満杞寲鐜囧垎鏋�" lazy name="businessInversionRateSummaryRef"> - <BusinessInversionRateSummary - ref="businessInversionRateSummaryRef" - :query-params="queryParams" - /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> - -<script lang="ts" setup> -import * as DeptApi from '@/api/system/dept' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' -import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime' -import { defaultProps, handleTree } from '@/utils/tree' -import FunnelBusiness from './components/FunnelBusiness.vue' -import BusinessSummary from './components/BusinessSummary.vue' -import BusinessInversionRateSummary from './components/BusinessInversionRateSummary.vue' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -defineOptions({ name: 'CrmStatisticsFunnel' }) - -const queryParams = reactive({ - interval: 2, // WEEK, 鍛� - deptId: useUserStore().getUser.deptId, - userId: undefined, - times: [ - // 榛樿鏄剧ず鏈�杩戜竴鍛ㄧ殑鏁版嵁 - formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))), - formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))) - ] -}) - -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const deptList = ref<Tree[]>([]) // 閮ㄩ棬鏍戝舰缁撴瀯 -const userList = ref<UserApi.UserVO[]>([]) // 鍏ㄩ噺鐢ㄦ埛娓呭崟 - -/** 鏍规嵁閫夋嫨鐨勯儴闂ㄧ瓫閫夊憳宸ユ竻鍗� */ -const userListByDeptId = computed(() => - queryParams.deptId - ? userList.value.filter((u: UserApi.UserVO) => u.deptId === queryParams.deptId) - : [] -) - -const activeTab = ref('funnelRef') // 娲昏穬鏍囩 -const funnelRef = ref() // 閿�鍞紡鏂� -const businessSummaryRef = ref() // 鏂板鍟嗘満鍒嗘瀽 -const businessInversionRateSummaryRef = ref() // 鍟嗘満杞寲鐜囧垎鏋� - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - switch (activeTab.value) { - case 'funnelRef': - funnelRef.value?.loadData?.() - break - case 'businessSummaryRef': - businessSummaryRef.value?.loadData?.() - break - case 'businessInversionRateSummaryRef': - businessInversionRateSummaryRef.value?.loadData?.() - break - } -} - -/** 褰� activeTab 鏀瑰彉鏃讹紝鍒锋柊褰撳墠娲诲姩鐨� tab */ -watch(activeTab, () => { - handleQuery() -}) - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� */ -onMounted(async () => { - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) - userList.value = handleTree(await UserApi.getSimpleUserList()) -}) -</script> diff --git a/src/views/crm/statistics/performance/components/ContractCountPerformance.vue b/src/views/crm/statistics/performance/components/ContractCountPerformance.vue deleted file mode 100644 index fa5a897..0000000 --- a/src/views/crm/statistics/performance/components/ContractCountPerformance.vue +++ /dev/null @@ -1,236 +0,0 @@ -<!-- 鍛樺伐涓氱哗缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="tableData"> - <el-table-column - v-for="item in columnsData" - :key="item.prop" - :label="item.label" - :prop="item.prop" - align="center" - > - <template #default="scope"> - {{ scope.row[item.prop] }} - </template> - </el-table-column> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { EChartsOption } from 'echarts' -import { - StatisticsPerformanceApi, - StatisticsPerformanceRespVO -} from '@/api/crm/statistics/performance' - -defineOptions({ name: 'ContractCountPerformance' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsPerformanceRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '褰撴湀鍚堝悓鏁伴噺锛堜釜锛�', - type: 'line', - data: [] - }, - { - name: '涓婃湀鍚堝悓鏁伴噺锛堜釜锛�', - type: 'line', - data: [] - }, - { - name: '鍘诲勾鍚屾湀鍚堝悓鏁伴噺锛堜釜锛�', - type: 'line', - data: [] - }, - { - name: '鐜瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - }, - { - name: '鍚屾瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛鎬婚噺鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '鏁伴噺锛堜釜锛�', - axisTick: { - show: false - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - }, - { - type: 'value', - name: '', - axisTick: { - alignWithLabel: true, - lineStyle: { - width: 0 - } - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}%' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const performanceList = await StatisticsPerformanceApi.getContractCountPerformance( - props.queryParams - ) - - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => s.time) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.currentMonthCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastMonthCount - ) - echartsOption.series[3]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastMonthCount !== 0 - ? (((s.currentMonthCount - s.lastMonthCount) / s.lastMonthCount) * 100).toFixed(2) - : 'NULL' - ) - } - if (echartsOption.series && echartsOption.series[2] && echartsOption.series[2]['data']) { - echartsOption.series[2]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastYearCount - ) - echartsOption.series[4]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastYearCount !== 0 - ? (((s.currentMonthCount - s.lastYearCount) / s.lastYearCount) * 100).toFixed(2) - : 'NULL' - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = performanceList - convertListData() - loading.value = false -} - -// 鍒濆鍖栨暟鎹� -const columnsData = reactive([]) -const tableData = reactive([ - { title: '褰撴湀鍚堝悓鏁伴噺缁熻锛堜釜锛�' }, - { title: '涓婃湀鍚堝悓鏁伴噺缁熻锛堜釜锛�' }, - { title: '鍘诲勾褰撴湀鍚堝悓鏁伴噺缁熻锛堜釜锛�' }, - { title: '鐜瘮澧為暱鐜囷紙%锛�' }, - { title: '鍚屾瘮澧為暱鐜囷紙%锛�' } -]) - -// 瀹氫箟 convertListData 鏂规硶锛屾暟鎹鍒楄浆缃紝灞曠ず姣忔湀鏁版嵁 -const convertListData = () => { - const columnObj = { label: '鏃ユ湡', prop: 'title' } - columnsData.splice(0, columnsData.length) //娓呯┖鏁扮粍 - columnsData.push(columnObj) - - list.value.forEach((item, index) => { - const columnObj = { label: item.time, prop: 'prop' + index } - columnsData.push(columnObj) - tableData[0]['prop' + index] = item.currentMonthCount - tableData[1]['prop' + index] = item.lastMonthCount - tableData[2]['prop' + index] = item.lastYearCount - tableData[3]['prop' + index] = - item.lastMonthCount !== 0 - ? (((item.currentMonthCount - item.lastMonthCount) / item.lastMonthCount) * 100).toFixed(2) - : 'NULL' - tableData[4]['prop' + index] = - item.lastYearCount !== 0 - ? (((item.currentMonthCount - item.lastYearCount) / item.lastYearCount) * 100).toFixed(2) - : 'NULL' - }) -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(async () => { - await loadData() -}) -</script> diff --git a/src/views/crm/statistics/performance/components/ContractPricePerformance.vue b/src/views/crm/statistics/performance/components/ContractPricePerformance.vue deleted file mode 100644 index dd52d9f..0000000 --- a/src/views/crm/statistics/performance/components/ContractPricePerformance.vue +++ /dev/null @@ -1,236 +0,0 @@ -<!-- 鍛樺伐涓氱哗缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="tableData"> - <el-table-column - v-for="item in columnsData" - :key="item.prop" - :label="item.label" - :prop="item.prop" - align="center" - > - <template #default="scope"> - {{ scope.row[item.prop] }} - </template> - </el-table-column> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { EChartsOption } from 'echarts' -import { - StatisticsPerformanceApi, - StatisticsPerformanceRespVO -} from '@/api/crm/statistics/performance' - -defineOptions({ name: 'ContractPricePerformance' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsPerformanceRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '褰撴湀鍚堝悓閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '涓婃湀鍚堝悓閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '鍘诲勾鍚屾湀鍚堝悓閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '鐜瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - }, - { - name: '鍚屾瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛鎬婚噺鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '閲戦锛堝厓锛�', - axisTick: { - show: false - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - }, - { - type: 'value', - name: '', - axisTick: { - alignWithLabel: true, - lineStyle: { - width: 0 - } - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}%' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const performanceList = await StatisticsPerformanceApi.getContractPricePerformance( - props.queryParams - ) - - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => s.time) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.currentMonthCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastMonthCount - ) - echartsOption.series[3]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastMonthCount !== 0 - ? (((s.currentMonthCount - s.lastMonthCount) / s.lastMonthCount) * 100).toFixed(2) - : 'NULL' - ) - } - if (echartsOption.series && echartsOption.series[2] && echartsOption.series[2]['data']) { - echartsOption.series[2]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastYearCount - ) - echartsOption.series[4]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastYearCount !== 0 - ? (((s.currentMonthCount - s.lastYearCount) / s.lastYearCount) * 100).toFixed(2) - : 'NULL' - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = performanceList - convertListData() - loading.value = false -} - -// 鍒濆鍖栨暟鎹� -const columnsData = reactive([]) -const tableData = reactive([ - { title: '褰撴湀鍚堝悓閲戦缁熻锛堝厓锛�' }, - { title: '涓婃湀鍚堝悓閲戦缁熻锛堝厓锛�' }, - { title: '鍘诲勾褰撴湀鍚堝悓閲戦缁熻锛堝厓锛�' }, - { title: '鐜瘮澧為暱鐜囷紙%锛�' }, - { title: '鍚屾瘮澧為暱鐜囷紙%锛�' } -]) - -// 瀹氫箟 init 鏂规硶 -const convertListData = () => { - const columnObj = { label: '鏃ユ湡', prop: 'title' } - columnsData.splice(0, columnsData.length) //娓呯┖鏁扮粍 - columnsData.push(columnObj) - - list.value.forEach((item, index) => { - const columnObj = { label: item.time, prop: 'prop' + index } - columnsData.push(columnObj) - tableData[0]['prop' + index] = item.currentMonthCount - tableData[1]['prop' + index] = item.lastMonthCount - tableData[2]['prop' + index] = item.lastYearCount - tableData[3]['prop' + index] = - item.lastMonthCount !== 0 - ? (((item.currentMonthCount - item.lastMonthCount) / item.lastMonthCount) * 100).toFixed(2) - : 'NULL' - tableData[4]['prop' + index] = - item.lastYearCount !== 0 - ? (((item.currentMonthCount - item.lastYearCount) / item.lastYearCount) * 100).toFixed(2) - : 'NULL' - }) -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(async () => { - await loadData() -}) -</script> diff --git a/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue b/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue deleted file mode 100644 index 169f074..0000000 --- a/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue +++ /dev/null @@ -1,236 +0,0 @@ -<!-- 鍛樺伐涓氱哗缁熻 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="tableData"> - <el-table-column - v-for="item in columnsData" - :key="item.prop" - :label="item.label" - :prop="item.prop" - align="center" - > - <template #default="scope"> - {{ scope.row[item.prop] }} - </template> - </el-table-column> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { EChartsOption } from 'echarts' -import { - StatisticsPerformanceApi, - StatisticsPerformanceRespVO -} from '@/api/crm/statistics/performance' - -defineOptions({ name: 'ContractPricePerformance' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsPerformanceRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細绾靛悜 */ -const echartsOption = reactive<EChartsOption>({ - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: {}, - series: [ - { - name: '褰撴湀鍥炴閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '涓婃湀鍥炴閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '鍘诲勾鍚屾湀鍥炴閲戦锛堝厓锛�', - type: 'line', - data: [] - }, - { - name: '鐜瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - }, - { - name: '鍚屾瘮澧為暱鐜囷紙%锛�', - type: 'line', - yAxisIndex: 1, - data: [] - } - ], - toolbox: { - feature: { - dataZoom: { - xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '瀹㈡埛鎬婚噺鍒嗘瀽' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - yAxis: [ - { - type: 'value', - name: '閲戦锛堝厓锛�', - axisTick: { - show: false - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - }, - { - type: 'value', - name: '', - axisTick: { - alignWithLabel: true, - lineStyle: { - width: 0 - } - }, - axisLabel: { - color: '#BDBDBD', - formatter: '{value}%' - }, - /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */ - axisLine: { - lineStyle: { - color: '#BDBDBD' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#e6e6e6' - } - } - } - ], - xAxis: { - type: 'category', - name: '鏃ユ湡', - data: [] - } -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const performanceList = await StatisticsPerformanceApi.getReceivablePricePerformance( - props.queryParams - ) - - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.xAxis && echartsOption.xAxis['data']) { - echartsOption.xAxis['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => s.time) - } - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.currentMonthCount - ) - } - if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) { - echartsOption.series[1]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastMonthCount - ) - echartsOption.series[3]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastMonthCount !== 0 - ? (((s.currentMonthCount - s.lastMonthCount) / s.lastMonthCount) * 100).toFixed(2) - : 'NULL' - ) - } - if (echartsOption.series && echartsOption.series[2] && echartsOption.series[1]['data']) { - echartsOption.series[2]['data'] = performanceList.map( - (s: StatisticsPerformanceRespVO) => s.lastYearCount - ) - echartsOption.series[4]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => - s.lastYearCount !== 0 - ? (((s.currentMonthCount - s.lastYearCount) / s.lastYearCount) * 100).toFixed(2) - : 'NULL' - ) - } - - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = performanceList - convertListData() - loading.value = false -} - -// 鍒濆鍖栨暟鎹� -const columnsData = reactive([]) -const tableData = reactive([ - { title: '褰撴湀鍥炴閲戦缁熻锛堝厓锛�' }, - { title: '涓婃湀鍥炴閲戦缁熻锛堝厓锛�' }, - { title: '鍘诲勾褰撴湀鍥炴閲戦缁熻锛堝厓锛�' }, - { title: '鐜瘮澧為暱鐜囷紙%锛�' }, - { title: '鍚屾瘮澧為暱鐜囷紙%锛�' } -]) - -// 瀹氫箟 init 鏂规硶 -const convertListData = () => { - const columnObj = { label: '鏃ユ湡', prop: 'title' } - columnsData.splice(0, columnsData.length) //娓呯┖鏁扮粍 - columnsData.push(columnObj) - - list.value.forEach((item, index) => { - const columnObj = { label: item.time, prop: 'prop' + index } - columnsData.push(columnObj) - tableData[0]['prop' + index] = item.currentMonthCount - tableData[1]['prop' + index] = item.lastMonthCount - tableData[2]['prop' + index] = item.lastYearCount - tableData[3]['prop' + index] = - item.lastMonthCount !== 0 - ? (((item.currentMonthCount - item.lastMonthCount) / item.lastMonthCount) * 100).toFixed(2) - : 'NULL' - tableData[4]['prop' + index] = - item.lastYearCount !== 0 - ? (((item.currentMonthCount - item.lastYearCount) / item.lastYearCount) * 100).toFixed(2) - : 'NULL' - }) -} - -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(async () => { - await loadData() -}) -</script> diff --git a/src/views/crm/statistics/performance/index.vue b/src/views/crm/statistics/performance/index.vue deleted file mode 100644 index 822afec..0000000 --- a/src/views/crm/statistics/performance/index.vue +++ /dev/null @@ -1,146 +0,0 @@ -<!-- 鏁版嵁缁熻 - 鍛樺伐涓氱哗鍒嗘瀽 --> -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="閫夋嫨骞翠唤" prop="orderDate"> - <el-date-picker - v-model="queryParams.times[0]" - class="!w-240px" - type="year" - value-format="YYYY" - :default-time="[new Date().getFullYear()]" - /> - </el-form-item> - <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId"> - <el-tree-select - v-model="queryParams.deptId" - class="!w-240px" - :data="deptList" - :props="defaultProps" - check-strictly - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - @change="queryParams.userId = undefined" - /> - </el-form-item> - <el-form-item label="鍛樺伐" prop="userId"> - <el-select v-model="queryParams.userId" class="!w-240px" placeholder="鍛樺伐" clearable> - <el-option - v-for="(user, index) in userListByDeptId" - :label="user.nickname" - :value="user.id" - :key="index" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" /> 鎼滅储 </el-button> - <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆 </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍛樺伐涓氱哗缁熻 --> - <el-col> - <el-tabs v-model="activeTab"> - <!-- 鍛樺伐鍚堝悓缁熻 --> - <el-tab-pane label="鍛樺伐鍚堝悓鏁伴噺缁熻" name="ContractCountPerformance" lazy> - <ContractCountPerformance :query-params="queryParams" ref="ContractCountPerformanceRef" /> - </el-tab-pane> - <!-- 鍛樺伐鍚堝悓閲戦缁熻 --> - <el-tab-pane label="鍛樺伐鍚堝悓閲戦缁熻" name="ContractPricePerformance" lazy> - <ContractPricePerformance :query-params="queryParams" ref="ContractPricePerformanceRef" /> - </el-tab-pane> - <!-- 鍛樺伐鍥炴閲戦缁熻 --> - <el-tab-pane label="鍛樺伐鍥炴閲戦缁熻" name="ReceivablePricePerformance" lazy> - <ReceivablePricePerformance - :query-params="queryParams" - ref="ReceivablePricePerformanceRef" - /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> - -<script lang="ts" setup> -import * as DeptApi from '@/api/system/dept' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' -import { beginOfDay, endOfDay, formatDate } from '@/utils/formatTime' -import { defaultProps, handleTree } from '@/utils/tree' -import ContractCountPerformance from './components/ContractCountPerformance.vue' -import ContractPricePerformance from './components/ContractPricePerformance.vue' -import ReceivablePricePerformance from './components/ReceivablePricePerformance.vue' - -defineOptions({ name: 'CrmStatisticsCustomer' }) - -const queryParams = reactive({ - deptId: useUserStore().getUser.deptId, - userId: undefined, - times: [ - formatDate(beginOfDay(new Date(new Date().getFullYear(), 0, 1))), - formatDate(endOfDay(new Date(new Date().getFullYear(), 11, 31))) - ] -}) - -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const deptList = ref<Tree[]>([]) // 閮ㄩ棬鏍戝舰缁撴瀯 -const userList = ref<UserApi.UserVO[]>([]) // 鍏ㄩ噺鐢ㄦ埛娓呭崟 -// 鏍规嵁閫夋嫨鐨勯儴闂ㄧ瓫閫夊憳宸ユ竻鍗� -const userListByDeptId = computed(() => - queryParams.deptId - ? userList.value.filter((u: UserApi.UserVO) => u.deptId === queryParams.deptId) - : [] -) - -// 娲昏穬鏍囩 -const activeTab = ref('ContractCountPerformance') -const ContractCountPerformanceRef = ref() // 鍛樺伐鍚堝悓鏁伴噺缁熻 -const ContractPricePerformanceRef = ref() // 鍛樺伐鍚堝悓閲戦缁熻 -const ReceivablePricePerformanceRef = ref() // 鍛樺伐鍥炴閲戦缁熻 - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - // 浠� queryParams.times[0] 涓幏鍙栧埌浜嗗勾浠� - const selectYear = parseInt(queryParams.times[0]) - queryParams.times[0] = formatDate(beginOfDay(new Date(selectYear, 0, 1))) - queryParams.times[1] = formatDate(endOfDay(new Date(selectYear, 11, 31))) - - // 鎵ц鏌ヨ - switch (activeTab.value) { - case 'ContractCountPerformance': - ContractCountPerformanceRef.value?.loadData?.() - break - case 'ContractPricePerformance': - ContractPricePerformanceRef.value?.loadData?.() - break - case 'ReceivablePricePerformance': - ReceivablePricePerformanceRef.value?.loadData?.() - break - } -} - -// 褰� activeTab 鏀瑰彉鏃讹紝鍒锋柊褰撳墠娲诲姩鐨� tab -watch(activeTab, () => { - handleQuery() -}) - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -// 鍔犺浇閮ㄩ棬鏍� -onMounted(async () => { - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) - userList.value = handleTree(await UserApi.getSimpleUserList()) -}) -</script> diff --git a/src/views/crm/statistics/portrait/components/PortraitCustomerArea.vue b/src/views/crm/statistics/portrait/components/PortraitCustomerArea.vue deleted file mode 100644 index 513936c..0000000 --- a/src/views/crm/statistics/portrait/components/PortraitCustomerArea.vue +++ /dev/null @@ -1,147 +0,0 @@ -<!-- 瀹㈡埛鍩庡競鍒嗗竷 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-row :gutter="20"> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-col> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption2" /> - </el-skeleton> - </el-col> - </el-row> - </el-card> -</template> -<script lang="ts" setup> -import { EChartsOption } from 'echarts' -import china from '@/assets/map/json/china.json' -import echarts from '@/plugins/echarts' -import { - CrmStatisticCustomerAreaRespVO, - StatisticsPortraitApi -} from '@/api/crm/statistics/portrait' -import { areaReplace } from '@/utils' - -defineOptions({ name: 'PortraitCustomerArea' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -// 娉ㄥ唽鍦板浘 -echarts?.registerMap('china', china as any) - -const loading = ref(false) // 鍔犺浇涓� -const areaStatisticsList = ref<CrmStatisticCustomerAreaRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鍦板浘閰嶇疆锛堝叏閮ㄥ鎴凤級 */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '鍏ㄩ儴瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item', - showDelay: 0, - transitionDuration: 0.2 - }, - visualMap: { - text: ['楂�', '浣�'], - realtime: false, - calculable: true, - top: 'middle', - inRange: { - color: ['#fff', '#3b82f6'] - } - }, - series: [ - { - name: '瀹㈡埛鍦板煙鍒嗗竷', - type: 'map', - map: 'china', - roam: false, - selectedMode: false, - data: [] - } - ] -}) as EChartsOption - -/** 鍦板浘閰嶇疆锛堟垚浜ゅ鎴凤級 */ -const echartsOption2 = reactive<EChartsOption>({ - title: { - text: '鎴愪氦瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item', - showDelay: 0, - transitionDuration: 0.2 - }, - visualMap: { - text: ['楂�', '浣�'], - realtime: false, - calculable: true, - top: 'middle', - inRange: { - color: ['#fff', '#3b82f6'] - } - }, - series: [ - { - name: '瀹㈡埛鍦板煙鍒嗗竷', - type: 'map', - map: 'china', - roam: false, - selectedMode: false, - data: [] - } - ] -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const areaList = await StatisticsPortraitApi.getCustomerArea(props.queryParams) - areaStatisticsList.value = areaList.map((item: CrmStatisticCustomerAreaRespVO) => { - return { - ...item, - areaName: areaReplace(item.areaName) - } - }) - buildLeftMap() - buildRightMap() - loading.value = false -} -defineExpose({ loadData }) - -const buildLeftMap = () => { - let min = 0 - let max = 0 - echartsOption.series![0].data = areaStatisticsList.value.map((item) => { - min = Math.min(min, item.customerCount || 0) - max = Math.max(max, item.customerCount || 0) - return { ...item, name: item.areaName, value: item.customerCount || 0 } - }) - echartsOption.visualMap!['min'] = min - echartsOption.visualMap!['max'] = max -} - -const buildRightMap = () => { - let min = 0 - let max = 0 - echartsOption2.series![0].data = areaStatisticsList.value.map((item) => { - min = Math.min(min, item.dealCount || 0) - max = Math.max(max, item.dealCount || 0) - return { ...item, name: item.areaName, value: item.dealCount || 0 } - }) - echartsOption2.visualMap!['min'] = min - echartsOption2.visualMap!['max'] = max -} - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/portrait/components/PortraitCustomerIndustry.vue b/src/views/crm/statistics/portrait/components/PortraitCustomerIndustry.vue deleted file mode 100644 index d426993..0000000 --- a/src/views/crm/statistics/portrait/components/PortraitCustomerIndustry.vue +++ /dev/null @@ -1,198 +0,0 @@ -<!-- 瀹㈡埛琛屼笟鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-row :gutter="20"> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-col> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption2" /> - </el-skeleton> - </el-col> - </el-row> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" label="瀹㈡埛琛屼笟" prop="industryId" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛涓暟" min-width="200" prop="customerCount" /> - <el-table-column align="center" label="鎴愪氦涓暟" min-width="200" prop="dealCount" /> - <el-table-column align="center" label="琛屼笟鍗犳瘮(%)" min-width="200" prop="industryPortion" /> - <el-table-column align="center" label="鎴愪氦鍗犳瘮(%)" min-width="200" prop="dealPortion" /> - </el-table> - </el-card> -</template> -<script lang="ts" setup> -import { - CrmStatisticCustomerIndustryRespVO, - StatisticsPortraitApi -} from '@/api/crm/statistics/portrait' -import { EChartsOption } from 'echarts' -import { DICT_TYPE, getDictLabel } from '@/utils/dict' -import { erpCalculatePercentage, getSumValue } from '@/utils' -import { isEmpty } from '@/utils/is' - -defineOptions({ name: 'PortraitCustomerIndustry' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticCustomerIndustryRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 楗煎浘閰嶇疆锛堝叏閮ㄥ鎴凤級 */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '鍏ㄩ儴瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鍏ㄩ儴瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鍏ㄩ儴瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 楗煎浘閰嶇疆锛堟垚浜ゅ鎴凤級 */ -const echartsOption2 = reactive<EChartsOption>({ - title: { - text: '鎴愪氦瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鎴愪氦瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鎴愪氦瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const industryList = await StatisticsPortraitApi.getCustomerIndustry(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = industryList.map((r: CrmStatisticCustomerIndustryRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), - value: r.customerCount - } - }) - } - // 2.2 鏇存柊 Echarts2 鏁版嵁 - if (echartsOption2.series && echartsOption2.series[0] && echartsOption2.series[0]['data']) { - echartsOption2.series[0]['data'] = industryList.map((r: CrmStatisticCustomerIndustryRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), - value: r.dealCount - } - }) - } - // 3. 璁$畻姣斾緥 - calculateProportion(industryList) - list.value = industryList - loading.value = false -} -defineExpose({ loadData }) - -/** 璁$畻姣斾緥 */ -const calculateProportion = (sourceList: CrmStatisticCustomerIndustryRespVO[]) => { - if (isEmpty(sourceList)) { - return - } - // 杩欓噷绫诲瀷涓㈠け浜嗘墍浠ラ噸鏂版悶涓彉閲� - const list = sourceList as unknown as CrmStatisticCustomerIndustryRespVO[] - const sumCustomerCount = getSumValue(list.map((item) => item.customerCount)) - const sumDealCount = getSumValue(list.map((item) => item.dealCount)) - list.forEach((item) => { - item.industryPortion = - item.customerCount === 0 ? 0 : erpCalculatePercentage(item.customerCount, sumCustomerCount) - item.dealPortion = - item.dealCount === 0 ? 0 : erpCalculatePercentage(item.dealCount, sumDealCount) - }) -} - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/portrait/components/PortraitCustomerLevel.vue b/src/views/crm/statistics/portrait/components/PortraitCustomerLevel.vue deleted file mode 100644 index 653feef..0000000 --- a/src/views/crm/statistics/portrait/components/PortraitCustomerLevel.vue +++ /dev/null @@ -1,198 +0,0 @@ -<!-- 瀹㈡埛鏉ユ簮鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-row :gutter="20"> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-col> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption2" /> - </el-skeleton> - </el-col> - </el-row> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" label="瀹㈡埛绾у埆" prop="level" width="200"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛涓暟" min-width="200" prop="customerCount" /> - <el-table-column align="center" label="鎴愪氦涓暟" min-width="200" prop="dealCount" /> - <el-table-column align="center" label="绾у埆鍗犳瘮(%)" min-width="200" prop="levelPortion" /> - <el-table-column align="center" label="鎴愪氦鍗犳瘮(%)" min-width="200" prop="dealPortion" /> - </el-table> - </el-card> -</template> -<script lang="ts" setup> -import { - CrmStatisticCustomerLevelRespVO, - StatisticsPortraitApi -} from '@/api/crm/statistics/portrait' -import { EChartsOption } from 'echarts' -import { DICT_TYPE, getDictLabel } from '@/utils/dict' -import { erpCalculatePercentage, getSumValue } from '@/utils' -import { isEmpty } from '@/utils/is' - -defineOptions({ name: 'PortraitCustomerLevel' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticCustomerLevelRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 楗煎浘閰嶇疆锛堝叏閮ㄥ鎴凤級 */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '鍏ㄩ儴瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鍏ㄩ儴瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鍏ㄩ儴瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 楗煎浘閰嶇疆锛堟垚浜ゅ鎴凤級 */ -const echartsOption2 = reactive<EChartsOption>({ - title: { - text: '鎴愪氦瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鎴愪氦瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鎴愪氦瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const levelList = await StatisticsPortraitApi.getCustomerLevel(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = levelList.map((r: CrmStatisticCustomerLevelRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.customerCount - } - }) - } - // 2.2 鏇存柊 Echarts2 鏁版嵁 - if (echartsOption2.series && echartsOption2.series[0] && echartsOption2.series[0]['data']) { - echartsOption2.series[0]['data'] = levelList.map((r: CrmStatisticCustomerLevelRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.dealCount - } - }) - } - // 3. 璁$畻姣斾緥 - calculateProportion(levelList) - list.value = levelList - loading.value = false -} -defineExpose({ loadData }) - -/** 璁$畻姣斾緥 */ -const calculateProportion = (levelList: CrmStatisticCustomerLevelRespVO[]) => { - if (isEmpty(levelList)) { - return - } - // 杩欓噷绫诲瀷涓㈠け浜嗘墍浠ラ噸鏂版悶涓彉閲� - const list = levelList as unknown as CrmStatisticCustomerLevelRespVO[] - const sumCustomerCount = getSumValue(list.map((item) => item.customerCount)) - const sumDealCount = getSumValue(list.map((item) => item.dealCount)) - list.forEach((item) => { - item.levelPortion = - item.customerCount === 0 ? 0 : erpCalculatePercentage(item.customerCount, sumCustomerCount) - item.dealPortion = - item.dealCount === 0 ? 0 : erpCalculatePercentage(item.dealCount, sumDealCount) - }) -} - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/portrait/components/PortraitCustomerSource.vue b/src/views/crm/statistics/portrait/components/PortraitCustomerSource.vue deleted file mode 100644 index ade6445..0000000 --- a/src/views/crm/statistics/portrait/components/PortraitCustomerSource.vue +++ /dev/null @@ -1,198 +0,0 @@ -<!-- 瀹㈡埛鏉ユ簮鍒嗘瀽 --> -<template> - <!-- Echarts鍥� --> - <el-card shadow="never"> - <el-row :gutter="20"> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-col> - <el-col :span="12"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption2" /> - </el-skeleton> - </el-col> - </el-row> - </el-card> - - <!-- 缁熻鍒楄〃 --> - <el-card class="mt-16px" shadow="never"> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="搴忓彿" type="index" width="80" /> - <el-table-column align="center" label="瀹㈡埛鏉ユ簮" prop="source" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹㈡埛涓暟" min-width="200" prop="customerCount" /> - <el-table-column align="center" label="鎴愪氦涓暟" min-width="200" prop="dealCount" /> - <el-table-column align="center" label="鏉ユ簮鍗犳瘮(%)" min-width="200" prop="sourcePortion" /> - <el-table-column align="center" label="鎴愪氦鍗犳瘮(%)" min-width="200" prop="dealPortion" /> - </el-table> - </el-card> -</template> -<script lang="ts" setup> -import { - CrmStatisticCustomerSourceRespVO, - StatisticsPortraitApi -} from '@/api/crm/statistics/portrait' -import { EChartsOption } from 'echarts' -import { DICT_TYPE, getDictLabel } from '@/utils/dict' -import { isEmpty } from '@/utils/is' -import { erpCalculatePercentage, getSumValue } from '@/utils' - -defineOptions({ name: 'PortraitCustomerSource' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<CrmStatisticCustomerSourceRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 楗煎浘閰嶇疆锛堝叏閮ㄥ鎴凤級 */ -const echartsOption = reactive<EChartsOption>({ - title: { - text: '鍏ㄩ儴瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鍏ㄩ儴瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鍏ㄩ儴瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 楗煎浘閰嶇疆锛堟垚浜ゅ鎴凤級 */ -const echartsOption2 = reactive<EChartsOption>({ - title: { - text: '鎴愪氦瀹㈡埛', - left: 'center' - }, - tooltip: { - trigger: 'item' - }, - legend: { - orient: 'vertical', - left: 'left' - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '鎴愪氦瀹㈡埛' } // 淇濆瓨涓哄浘鐗� - } - }, - series: [ - { - name: '鎴愪氦瀹㈡埛', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2 - }, - label: { - show: false, - position: 'center' - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold' - } - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 鑾峰彇缁熻鏁版嵁 */ -const loadData = async () => { - // 1. 鍔犺浇缁熻鏁版嵁 - loading.value = true - const sourceList = await StatisticsPortraitApi.getCustomerSource(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) { - echartsOption.series[0]['data'] = sourceList.map((r: CrmStatisticCustomerSourceRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.customerCount - } - }) - } - // 2.2 鏇存柊 Echarts2 鏁版嵁 - if (echartsOption2.series && echartsOption2.series[0] && echartsOption2.series[0]['data']) { - echartsOption2.series[0]['data'] = sourceList.map((r: CrmStatisticCustomerSourceRespVO) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.dealCount - } - }) - } - // 3. 璁$畻姣斾緥 - calculateProportion(sourceList) - list.value = sourceList - loading.value = false -} -defineExpose({ loadData }) - -/** 璁$畻姣斾緥 */ -const calculateProportion = (sourceList: CrmStatisticCustomerSourceRespVO[]) => { - if (isEmpty(sourceList)) { - return - } - // 杩欓噷绫诲瀷涓㈠け浜嗘墍浠ラ噸鏂版悶涓彉閲� - const list = sourceList as unknown as CrmStatisticCustomerSourceRespVO[] - const sumCustomerCount = getSumValue(list.map((item) => item.customerCount)) - const sumDealCount = getSumValue(list.map((item) => item.dealCount)) - list.forEach((item) => { - item.sourcePortion = - item.customerCount === 0 ? 0 : erpCalculatePercentage(item.customerCount, sumCustomerCount) - item.dealPortion = - item.dealCount === 0 ? 0 : erpCalculatePercentage(item.dealCount, sumDealCount) - }) -} - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/portrait/index.vue b/src/views/crm/statistics/portrait/index.vue deleted file mode 100644 index 71807e1..0000000 --- a/src/views/crm/statistics/portrait/index.vue +++ /dev/null @@ -1,156 +0,0 @@ -<!-- 鏁版嵁缁熻 - 瀹㈡埛鐢诲儚 --> -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鏃堕棿鑼冨洿" prop="orderDate"> - <el-date-picker - v-model="queryParams.times" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - :shortcuts="defaultShortcuts" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId"> - <el-tree-select - v-model="queryParams.deptId" - :data="deptList" - :props="defaultProps" - check-strictly - class="!w-240px" - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - @change="queryParams.userId = undefined" - /> - </el-form-item> - <el-form-item label="鍛樺伐" prop="userId"> - <el-select v-model="queryParams.userId" class="!w-240px" clearable placeholder="鍛樺伐"> - <el-option - v-for="(user, index) in userListByDeptId" - :key="index" - :label="user.nickname" - :value="user.id" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 瀹㈡埛缁熻 --> - <el-col> - <el-tabs v-model="activeTab"> - <!-- 鍩庡競鍒嗗竷鍒嗘瀽 --> - <el-tab-pane label="鍩庡競鍒嗗竷鍒嗘瀽" lazy name="areaRef"> - <PortraitCustomerArea ref="areaRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛绾у埆鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛绾у埆鍒嗘瀽" lazy name="levelRef"> - <PortraitCustomerLevel ref="levelRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛鏉ユ簮鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛鏉ユ簮鍒嗘瀽" lazy name="sourceRef"> - <PortraitCustomerSource ref="sourceRef" :query-params="queryParams" /> - </el-tab-pane> - <!-- 瀹㈡埛琛屼笟鍒嗘瀽 --> - <el-tab-pane label="瀹㈡埛琛屼笟鍒嗘瀽" lazy name="industryRef"> - <PortraitCustomerIndustry ref="industryRef" :query-params="queryParams" /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> - -<script lang="ts" setup> -import * as DeptApi from '@/api/system/dept' -import * as UserApi from '@/api/system/user' -import { useUserStore } from '@/store/modules/user' -import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime' -import { defaultProps, handleTree } from '@/utils/tree' -import PortraitCustomerArea from './components/PortraitCustomerArea.vue' -import PortraitCustomerIndustry from './components/PortraitCustomerIndustry.vue' -import PortraitCustomerSource from './components/PortraitCustomerSource.vue' -import PortraitCustomerLevel from './components/PortraitCustomerLevel.vue' - -defineOptions({ name: 'CrmStatisticsPortrait' }) - -const queryParams = reactive({ - deptId: useUserStore().getUser.deptId, - userId: undefined, - times: [ - // 榛樿鏄剧ず鏈�杩戜竴鍛ㄧ殑鏁版嵁 - formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))), - formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))) - ] -}) - -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const deptList = ref<Tree[]>([]) // 閮ㄩ棬鏍戝舰缁撴瀯 -const userList = ref<UserApi.UserVO[]>([]) // 鍏ㄩ噺鐢ㄦ埛娓呭崟 - -/** 鏍规嵁閫夋嫨鐨勯儴闂ㄧ瓫閫夊憳宸ユ竻鍗� */ -const userListByDeptId = computed(() => - queryParams.deptId - ? userList.value.filter((u: UserApi.UserVO) => u.deptId === queryParams.deptId) - : [] -) - -const activeTab = ref('areaRef') // 娲昏穬鏍囩 -const areaRef = ref() // 瀹㈡埛鍦板尯鍒嗗竷 -const levelRef = ref() // 瀹㈡埛绾у埆 -const sourceRef = ref() // 瀹㈡埛鏉ユ簮 -const industryRef = ref() // 瀹㈡埛琛屼笟 - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - switch (activeTab.value) { - case 'areaRef': - areaRef.value?.loadData?.() - break - case 'levelRef': - levelRef.value?.loadData?.() - break - case 'sourceRef': - sourceRef.value?.loadData?.() - break - case 'industryRef': - industryRef.value?.loadData?.() - break - } -} - -/** 褰� activeTab 鏀瑰彉鏃讹紝鍒锋柊褰撳墠娲诲姩鐨� tab */ -watch(activeTab, () => { - handleQuery() -}) - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� */ -onMounted(async () => { - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) - userList.value = handleTree(await UserApi.getSimpleUserList()) -}) -</script> diff --git a/src/views/crm/statistics/rank/components/ContactCountRank.vue b/src/views/crm/statistics/rank/components/ContactCountRank.vue deleted file mode 100644 index 5edc118..0000000 --- a/src/views/crm/statistics/rank/components/ContactCountRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 鏂板鑱旂郴浜烘暟鎺掕 --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="鍒涘缓浜�" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="鏂板鑱旂郴浜烘暟锛堜釜锛�" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'ContactCountRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '鏂板鑱旂郴浜烘暟鎺掕', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鏂板鑱旂郴浜烘暟鎺掕' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '鏂板鑱旂郴浜烘暟锛堜釜锛�' - }, - yAxis: { - type: 'category', - name: '鍒涘缓浜�' - } -}) as EChartsOption - -/** 鑾峰彇鏂板鑱旂郴浜烘暟鎺掕 */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getContactsCountRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/ContractCountRank.vue b/src/views/crm/statistics/rank/components/ContractCountRank.vue deleted file mode 100644 index fc50a6d..0000000 --- a/src/views/crm/statistics/rank/components/ContractCountRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 绛剧害鍚堝悓鎺掕 --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="绛捐浜�" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="绛剧害鍚堝悓鏁帮紙涓級" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'ContractCountRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '绛剧害鍚堝悓鎺掕', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '绛剧害鍚堝悓鎺掕' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '绛剧害鍚堝悓鏁帮紙涓級' - }, - yAxis: { - type: 'category', - name: '绛捐浜�' - } -}) as EChartsOption - -/** 鑾峰彇绛剧害鍚堝悓鎺掕 */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getContractCountRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/ContractPriceRank.vue b/src/views/crm/statistics/rank/components/ContractPriceRank.vue deleted file mode 100644 index b69ebd2..0000000 --- a/src/views/crm/statistics/rank/components/ContractPriceRank.vue +++ /dev/null @@ -1,105 +0,0 @@ -<!-- 鍚堝悓閲戦鎺掕 --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="绛捐浜�" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column - label="鍚堝悓閲戦锛堝厓锛�" - align="center" - prop="count" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'ContractPriceRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '鍚堝悓閲戦鎺掕', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鍚堝悓閲戦鎺掕' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '鍚堝悓閲戦锛堝厓锛�' - }, - yAxis: { - type: 'category', - name: '绛捐浜�' - } -}) as EChartsOption - -/** 鑾峰彇鍚堝悓閲戦鎺掕 */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getContractPriceRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/CustomerCountRank.vue b/src/views/crm/statistics/rank/components/CustomerCountRank.vue deleted file mode 100644 index b66a681..0000000 --- a/src/views/crm/statistics/rank/components/CustomerCountRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 鏂板瀹㈡埛鏁版帓琛� --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="鍒涘缓浜�" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="鏂板瀹㈡埛鏁帮紙涓級" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'CustomerCountRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '鏂板瀹㈡埛鏁版帓琛�', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鏂板瀹㈡埛鏁版帓琛�' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '鏂板瀹㈡埛鏁帮紙涓級' - }, - yAxis: { - type: 'category', - name: '鍒涘缓浜�' - } -}) as EChartsOption - -/** 鑾峰彇鏂板瀹㈡埛鏁版帓琛� */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getCustomerCountRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/FollowCountRank.vue b/src/views/crm/statistics/rank/components/FollowCountRank.vue deleted file mode 100644 index 43352ab..0000000 --- a/src/views/crm/statistics/rank/components/FollowCountRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 璺熻繘娆℃暟鎺掕 --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="鍛樺伐" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="璺熻繘娆℃暟锛堟锛�" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'FollowCountRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '璺熻繘娆℃暟鎺掕', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '璺熻繘娆℃暟鎺掕' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '璺熻繘娆℃暟锛堟锛�' - }, - yAxis: { - type: 'category', - name: '鍛樺伐' - } -}) as EChartsOption - -/** 鑾峰彇璺熻繘娆℃暟鎺掕 */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getFollowCountRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/FollowCustomerCountRank.vue b/src/views/crm/statistics/rank/components/FollowCustomerCountRank.vue deleted file mode 100644 index 92a2205..0000000 --- a/src/views/crm/statistics/rank/components/FollowCustomerCountRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 璺熻繘瀹㈡埛鏁版帓琛� --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="鍛樺伐" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="璺熻繘瀹㈡埛鏁帮紙涓級" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'FollowCustomerCountRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '璺熻繘瀹㈡埛鏁版帓琛�', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '璺熻繘瀹㈡埛鏁版帓琛�' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '璺熻繘瀹㈡埛鏁帮紙涓級' - }, - yAxis: { - type: 'category', - name: '鍛樺伐' - } -}) as EChartsOption - -/** 鑾峰彇璺熻繘瀹㈡埛鏁版帓琛� */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getFollowCustomerCountRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/ProductSalesRank.vue b/src/views/crm/statistics/rank/components/ProductSalesRank.vue deleted file mode 100644 index e2a02b7..0000000 --- a/src/views/crm/statistics/rank/components/ProductSalesRank.vue +++ /dev/null @@ -1,98 +0,0 @@ -<!-- 浜у搧閿�閲忔帓琛� --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="鍛樺伐" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column label="浜у搧閿�閲�" align="center" prop="count" min-width="200" /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' - -defineOptions({ name: 'ProductSalesRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '浜у搧閿�閲忔帓琛�', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '浜у搧閿�閲忔帓琛�' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '浜у搧閿�閲�' - }, - yAxis: { - type: 'category', - name: '鍛樺伐' - } -}) as EChartsOption - -/** 鑾峰彇浜у搧閿�閲忔帓琛� */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getProductSalesRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/components/ReceivablePriceRank.vue b/src/views/crm/statistics/rank/components/ReceivablePriceRank.vue deleted file mode 100644 index 06d7d9f..0000000 --- a/src/views/crm/statistics/rank/components/ReceivablePriceRank.vue +++ /dev/null @@ -1,106 +0,0 @@ -<!-- 鍥炴閲戦鎺掕 --> -<template> - <!-- 鏌辩姸鍥� --> - <el-card shadow="never"> - <el-skeleton :loading="loading" animated> - <Echart :height="500" :options="echartsOption" /> - </el-skeleton> - </el-card> - - <!-- 鎺掕鍒楄〃 --> - <el-card shadow="never" class="mt-16px"> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃鎺掑悕" align="center" type="index" width="80" /> - <el-table-column label="绛捐浜�" align="center" prop="nickname" min-width="200" /> - <el-table-column label="閮ㄩ棬" align="center" prop="deptName" min-width="200" /> - <el-table-column - label="鍥炴閲戦锛堝厓锛�" - align="center" - prop="count" - min-width="200" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - </el-card> -</template> -<script setup lang="ts"> -import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank' -import { EChartsOption } from 'echarts' -import { clone } from 'lodash-es' -import { erpPriceTableColumnFormatter } from '@/utils' - -defineOptions({ name: 'ReceivablePriceRank' }) -const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟 - -const loading = ref(false) // 鍔犺浇涓� -const list = ref<StatisticsRankRespVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌辩姸鍥鹃厤缃細妯悜 */ -const echartsOption = reactive<EChartsOption>({ - dataset: { - dimensions: ['nickname', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { - name: '鍥炴閲戦鎺掕', - type: 'bar' - } - ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鍥炴閲戦鎺掕' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - xAxis: { - type: 'value', - name: '鍥炴閲戦锛堝厓锛�' - }, - yAxis: { - type: 'category', - name: '绛捐浜�', - nameGap: 30 - } -}) as EChartsOption - -/** 鑾峰彇鍥炴閲戦鎺掕 */ -const loadData = async () => { - // 1. 鍔犺浇鎺掕鏁版嵁 - loading.value = true - const rankingList = await StatisticsRankApi.getReceivablePriceRank(props.queryParams) - // 2.1 鏇存柊 Echarts 鏁版嵁 - if (echartsOption.dataset && echartsOption.dataset['source']) { - echartsOption.dataset['source'] = clone(rankingList).reverse() - } - // 2.2 鏇存柊鍒楄〃鏁版嵁 - list.value = rankingList - loading.value = false -} -defineExpose({ loadData }) - -/** 鍒濆鍖� */ -onMounted(() => { - loadData() -}) -</script> diff --git a/src/views/crm/statistics/rank/index.vue b/src/views/crm/statistics/rank/index.vue deleted file mode 100644 index 98340cc..0000000 --- a/src/views/crm/statistics/rank/index.vue +++ /dev/null @@ -1,163 +0,0 @@ -<!-- BI 鎺掕鐗� --> -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鏃堕棿鑼冨洿" prop="orderDate"> - <el-date-picker - v-model="queryParams.times" - :shortcuts="defaultShortcuts" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - /> - </el-form-item> - <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId"> - <el-tree-select - v-model="queryParams.deptId" - :data="deptList" - :props="defaultProps" - check-strictly - node-key="id" - placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鎺掕鏁版嵁 --> - <el-col> - <el-tabs v-model="activeTab"> - <!-- 鍚堝悓閲戦鎺掕 --> - <el-tab-pane label="鍚堝悓閲戦鎺掕" name="contractPriceRank" lazy> - <ContractPriceRank :query-params="queryParams" ref="contractPriceRankRef" /> - </el-tab-pane> - <!-- 鍥炴閲戦鎺掕 --> - <el-tab-pane label="鍥炴閲戦鎺掕" name="receivablePriceRank" lazy> - <ReceivablePriceRank :query-params="queryParams" ref="receivablePriceRankRef" /> - </el-tab-pane> - <!-- 绛剧害鍚堝悓鎺掕 --> - <el-tab-pane label="绛剧害鍚堝悓鎺掕" name="contractCountRank" lazy> - <ContractCountRank :query-params="queryParams" ref="contractCountRankRef" /> - </el-tab-pane> - <!-- 浜у搧閿�閲忔帓琛� --> - <el-tab-pane label="浜у搧閿�閲忔帓琛�" name="productSalesRank" lazy> - <ProductSalesRank :query-params="queryParams" ref="productSalesRankRef" /> - </el-tab-pane> - <!-- 鏂板瀹㈡埛鏁版帓琛� --> - <el-tab-pane label="鏂板瀹㈡埛鏁版帓琛�" name="customerCountRank" lazy> - <CustomerCountRank :query-params="queryParams" ref="customerCountRankRef" /> - </el-tab-pane> - <!-- 鏂板鑱旂郴浜烘暟鎺掕 --> - <el-tab-pane label="鏂板鑱旂郴浜烘暟鎺掕" name="contactCountRank" lazy> - <ContactCountRank :query-params="queryParams" ref="contactCountRankRef" /> - </el-tab-pane> - <!-- 璺熻繘娆℃暟鎺掕 --> - <el-tab-pane label="璺熻繘娆℃暟鎺掕" name="followCountRank" lazy> - <FollowCountRank :query-params="queryParams" ref="followCountRankRef" /> - </el-tab-pane> - <!-- 璺熻繘瀹㈡埛鏁版帓琛� --> - <el-tab-pane label="璺熻繘瀹㈡埛鏁版帓琛�" name="followCustomerCountRank" lazy> - <FollowCustomerCountRank :query-params="queryParams" ref="followCustomerCountRankRef" /> - </el-tab-pane> - </el-tabs> - </el-col> -</template> -<script lang="ts" setup> -import ContractPriceRank from './components/ContractPriceRank.vue' -import ReceivablePriceRank from './components/ReceivablePriceRank.vue' -import ContractCountRank from './components/ContractCountRank.vue' -import ProductSalesRank from './components/ProductSalesRank.vue' -import CustomerCountRank from './components/CustomerCountRank.vue' -import ContactCountRank from './components/ContactCountRank.vue' -import FollowCountRank from './components/FollowCountRank.vue' -import FollowCustomerCountRank from './components/FollowCustomerCountRank.vue' -import { defaultProps, handleTree } from '@/utils/tree' -import * as DeptApi from '@/api/system/dept' -import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime' -import { useUserStore } from '@/store/modules/user' - -defineOptions({ name: 'CrmStatisticsRank' }) - -const queryParams = reactive({ - deptId: useUserStore().getUser.deptId, - times: [ - // 榛樿鏄剧ず鏈�杩戜竴鍛ㄧ殑鏁版嵁 - formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))), - formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))) - ] -}) - -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const deptList = ref<Tree[]>([]) // 鏍戝舰缁撴瀯 -const activeTab = ref('contractPriceRank') -const contractPriceRankRef = ref() // ContractPriceRank 缁勪欢鐨勫紩鐢� -const receivablePriceRankRef = ref() // ReceivablePriceRank 缁勪欢鐨勫紩鐢� -const contractCountRankRef = ref() // ContractCountRank 缁勪欢鐨勫紩鐢� -const productSalesRankRef = ref() // ProductSalesRank 缁勪欢鐨勫紩鐢� -const customerCountRankRef = ref() // CustomerCountRank 缁勪欢鐨勫紩鐢� -const contactCountRankRef = ref() // ContactCountRank 缁勪欢鐨勫紩鐢� -const followCountRankRef = ref() // FollowCountRank 缁勪欢鐨勫紩鐢� -const followCustomerCountRankRef = ref() // FollowCustomerCountRank 缁勪欢鐨勫紩鐢� - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - switch (activeTab.value) { - case 'contractPriceRank': // 鍚堝悓閲戦鎺掕 - contractPriceRankRef.value?.loadData?.() - break - case 'receivablePriceRank': // 鍥炴閲戦鎺掕 - receivablePriceRankRef.value?.loadData?.() - break - case 'contractCountRank': // 绛剧害鍚堝悓鎺掕 - contractCountRankRef.value?.loadData?.() - break - case 'productSalesRank': // 浜у搧閿�閲忔帓琛� - productSalesRankRef.value?.loadData?.() - break - case 'customerCountRank': // 鏂板瀹㈡埛鏁版帓琛� - customerCountRankRef.value?.loadData?.() - break - case 'contactCountRank': // 鏂板鑱旂郴浜烘暟鎺掕 - contactCountRankRef.value?.loadData?.() - break - case 'followCountRank': // 璺熻繘娆℃暟鎺掕 - followCountRankRef.value?.loadData?.() - break - case 'followCustomerCountRank': // 璺熻繘瀹㈡埛鏁版帓琛� - followCustomerCountRankRef.value?.loadData?.() - break - } -} - -// 褰� activeTab 鏀瑰彉鏃讹紝鍒锋柊褰撳墠娲诲姩鐨� tab -watch(activeTab, () => { - handleQuery() -}) - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -// 鍔犺浇閮ㄩ棬鏍� -onMounted(async () => { - deptList.value = handleTree(await DeptApi.getSimpleDeptList()) -}) -</script> -<style lang="scss" scoped></style> diff --git a/src/views/erp/finance/account/AccountForm.vue b/src/views/erp/finance/account/AccountForm.vue deleted file mode 100644 index 2f2e6f4..0000000 --- a/src/views/erp/finance/account/AccountForm.vue +++ /dev/null @@ -1,124 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="缂栫爜" prop="no"> - <el-input v-model="formData.no" placeholder="璇疯緭鍏ョ紪鐮�" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input v-model="formData.sort" placeholder="璇疯緭鍏ユ帓搴�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 缁撶畻 琛ㄥ崟 */ -defineOptions({ name: 'AccountForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - no: undefined, - remark: undefined, - status: undefined, - sort: undefined, - defaultStatus: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await AccountApi.getAccount(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as AccountVO - if (formType.value === 'create') { - await AccountApi.createAccount(data) - message.success(t('common.createSuccess')) - } else { - await AccountApi.updateAccount(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - no: undefined, - remark: undefined, - status: undefined, - sort: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/finance/account/index.vue b/src/views/erp/finance/account/index.vue deleted file mode 100644 index 8d85ef3..0000000 --- a/src/views/erp/finance/account/index.vue +++ /dev/null @@ -1,235 +0,0 @@ -<template> - <doc-alert - title="銆愯储鍔°�戦噰璐粯娆俱�侀攢鍞敹娆�" - url="https://doc.iocoder.cn/sale/finance-payment-receipt/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="缂栫爜" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ョ紪鐮�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:account:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:account:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="缂栫爜" align="center" prop="no" /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鏄惁榛樿" align="center" prop="defaultStatus"> - <template #default="scope"> - <el-switch - v-model="scope.row.defaultStatus" - :active-value="true" - :inactive-value="false" - @change="handleDefaultStatusChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:account:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:account:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <AccountForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import AccountForm from './AccountForm.vue' - -/** ERP 缁撶畻璐︽埛 鍒楄〃 */ -defineOptions({ name: 'ErpAccount' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<AccountVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - remark: undefined, - status: undefined, - name: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await AccountApi.getAccountPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await AccountApi.deleteAccount(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 淇敼榛樿鐘舵�� */ -const handleDefaultStatusChange = async (row: WarehouseVO) => { - try { - // 淇敼鐘舵�佺殑浜屾纭 - const text = row.defaultStatus ? '璁剧疆' : '鍙栨秷' - await message.confirm('纭瑕�' + text + '"' + row.name + '"榛樿鍚�?') - // 鍙戣捣淇敼鐘舵�� - await AccountApi.updateAccountDefaultStatus(row.id, row.defaultStatus) - // 鍒锋柊鍒楄〃 - await getList() - } catch (e) { - // 鍙栨秷鍚庯紝杩涜鎭㈠鎸夐挳 - row.defaultStatus = !row.defaultStatus - } -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await AccountApi.exportAccount(queryParams) - download.excel(data, 'ERP 缁撶畻璐︽埛.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/erp/finance/payment/FinancePaymentForm.vue b/src/views/erp/finance/payment/FinancePaymentForm.vue deleted file mode 100644 index 3da2e6e..0000000 --- a/src/views/erp/finance/payment/FinancePaymentForm.vue +++ /dev/null @@ -1,278 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浠樻鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浠樻鏃堕棿" prop="paymentTime"> - <el-date-picker - v-model="formData.paymentTime" - type="date" - value-format="x" - placeholder="閫夋嫨浠樻鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="formData.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-1/1" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璐㈠姟浜哄憳" prop="financeUserId"> - <el-select - v-model="formData.financeUserId" - clearable - filterable - placeholder="璇烽�夋嫨璐㈠姟浜哄憳" - class="!w-1/1" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="閲囪喘鍏ュ簱銆侀��璐у崟" name="item"> - <FinancePaymentItemForm - ref="itemFormRef" - :supplier-id="formData.supplierId" - :items="formData.items" - :disabled="disabled" - /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浠樻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍚堣浠樻" prop="totalPrice"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬閲戦" prop="discountPrice"> - <el-input-number - v-model="formData.discountPrice" - controls-position="right" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犻噾棰�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹為檯浠樻"> - <el-input - disabled - v-model="formData.paymentPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { FinancePaymentApi, FinancePaymentVO } from '@/api/erp/finance/payment' -import FinancePaymentItemForm from './components/FinancePaymentItemForm.vue' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import * as UserApi from '@/api/system/user' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 浠樻鍗曡〃鍗� */ -defineOptions({ name: 'FinancePaymentForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - supplierId: undefined, - accountId: undefined, - financeUserId: undefined, - paymentTime: undefined, - remark: undefined, - fileUrl: '', - totalPrice: 0, - discountPrice: 0, - paymentPrice: 0, - items: [], - no: undefined // 璁㈠崟鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - supplierId: [{ required: true, message: '渚涘簲鍟嗕笉鑳戒负绌�', trigger: 'blur' }], - paymentTime: [{ required: true, message: '璁㈠崟鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalPrice = val.items.reduce((prev, curr) => prev + curr.paymentPrice, 0) - formData.value.totalPrice = totalPrice - formData.value.paymentPrice = totalPrice - val.discountPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await FinancePaymentApi.getFinancePayment(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇渚涘簲鍟嗗垪琛� - supplierList.value = await SupplierApi.getSupplierSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as FinancePaymentVO - if (formType.value === 'create') { - await FinancePaymentApi.createFinancePayment(data) - message.success(t('common.createSuccess')) - } else { - await FinancePaymentApi.updateFinancePayment(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - supplierId: undefined, - accountId: undefined, - financeUserId: undefined, - paymentTime: undefined, - remark: undefined, - fileUrl: undefined, - totalPrice: 0, - discountPrice: 0, - paymentPrice: 0, - items: [], - no: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/finance/payment/components/FinancePaymentItemForm.vue b/src/views/erp/finance/payment/components/FinancePaymentItemForm.vue deleted file mode 100644 index ea0e085..0000000 --- a/src/views/erp/finance/payment/components/FinancePaymentItemForm.vue +++ /dev/null @@ -1,182 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="閲囪喘鍗曟嵁缂栧彿" min-width="200"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.bizNo" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴斾粯閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="宸蹭粯閲戦" prop="paidPrice" fixed="right" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.paidPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏈浠樻" prop="paymentPrice" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.paymentPrice`" class="mb-0px!"> - <el-input-number - v-model="row.paymentPrice" - controls-position="right" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleOpenPurchaseIn" round>+ 娣诲姞閲囪喘鍏ュ簱鍗�</el-button> - <el-button @click="handleOpenPurchaseReturn" round>+ 娣诲姞閲囪喘閫�璐у崟</el-button> - </el-row> - - <!-- 鍙粯娆剧殑銆愰噰璐叆搴撳崟銆戝垪琛� --> - <PurchaseInPaymentEnableList - ref="purchaseInPaymentEnableListRef" - @success="handleAddPurchaseIn" - /> - <!-- 鍙粯娆剧殑銆愰噰璐叆搴撳崟銆戝垪琛� --> - <PurchaseReturnRefundEnableList - ref="purchaseReturnRefundEnableListRef" - @success="handleAddPurchaseReturn" - /> -</template> -<script setup lang="ts"> -import { ProductVO } from '@/api/erp/product/product' -import { erpPriceInputFormatter, getSumValue } from '@/utils' -import PurchaseInPaymentEnableList from '@/views/erp/purchase/in/components/PurchaseInPaymentEnableList.vue' -import PurchaseReturnRefundEnableList from '@/views/erp/purchase/return/components/PurchaseReturnRefundEnableList.vue' -import { PurchaseInVO } from '@/api/erp/purchase/in' -import { ErpBizType } from '@/utils/constants' -import { PurchaseReturnVO } from '@/api/erp/purchase/return' - -const props = defineProps<{ - items: undefined - supplierId: undefined - disabled: false -}>() -const message = useMessage() - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - paymentPrice: [{ required: true, message: '鏈浠樻涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃叆搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['totalPrice', 'paidPrice', 'paymentPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - return sums -} - -/** 鏂板銆愰噰璐叆搴撱�戞寜閽搷浣� */ -const purchaseInPaymentEnableListRef = ref() -const handleOpenPurchaseIn = () => { - if (!props.supplierId) { - message.error('璇烽�夋嫨渚涘簲鍟�') - return - } - purchaseInPaymentEnableListRef.value.open(props.supplierId) -} -const handleAddPurchaseIn = (rows: PurchaseInVO[]) => { - rows.forEach((row) => { - formData.value.push({ - bizId: row.id, - bizType: ErpBizType.PURCHASE_IN, - bizNo: row.no, - totalPrice: row.totalPrice, - paidPrice: row.paymentPrice, - paymentPrice: row.totalPrice - row.paymentPrice - }) - }) -} - -/** 鏂板銆愰噰璐��璐с�戞寜閽搷浣� */ -const purchaseReturnRefundEnableListRef = ref() -const handleOpenPurchaseReturn = () => { - if (!props.supplierId) { - message.error('璇烽�夋嫨渚涘簲鍟�') - return - } - purchaseReturnRefundEnableListRef.value.open(props.supplierId) -} -const handleAddPurchaseReturn = (rows: PurchaseReturnVO[]) => { - rows.forEach((row) => { - formData.value.push({ - bizId: row.id, - bizType: ErpBizType.PURCHASE_RETURN, - bizNo: row.no, - totalPrice: -row.totalPrice, - paidPrice: -row.refundPrice, - paymentPrice: -row.totalPrice + row.refundPrice - }) - }) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) -</script> diff --git a/src/views/erp/finance/payment/index.vue b/src/views/erp/finance/payment/index.vue deleted file mode 100644 index 56bc83d..0000000 --- a/src/views/erp/finance/payment/index.vue +++ /dev/null @@ -1,394 +0,0 @@ -<template> - <doc-alert - title="銆愯储鍔°�戦噰璐粯娆俱�侀攢鍞敹娆�" - url="https://doc.iocoder.cn/sale/finance-payment-receipt/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="浠樻鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヤ粯娆惧崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浠樻鏃堕棿" prop="paymentTime"> - <el-date-picker - v-model="queryParams.paymentTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涗緵搴斿晢" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璐㈠姟浜哄憳" prop="financeUserId"> - <el-select - v-model="queryParams.financeUserId" - clearable - filterable - placeholder="璇烽�夋嫨璐㈠姟浜哄憳" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠樻璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨浠樻璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="閲囪喘鍗曞彿" prop="bizNo"> - <el-input - v-model="queryParams.bizNo" - placeholder="璇疯緭鍏ラ噰璐崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:finance-payment:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:finance-payment:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:finance-payment:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="浠樻鍗曞彿" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="浠樻鏃堕棿" - align="center" - prop="paymentTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column label="璐㈠姟浜哄憳" align="center" prop="financeUserName" /> - <el-table-column label="浠樻璐︽埛" align="center" prop="accountName" /> - <el-table-column - label="鍚堣浠樻" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="浼樻儬閲戦" - align="center" - prop="discountPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="瀹為檯浠樻" - align="center" - prop="paymentPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:finance-payment:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:finance-payment:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:finance-payment:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:finance-payment:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:finance-payment:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <FinancePaymentForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { FinancePaymentApi, FinancePaymentVO } from '@/api/erp/finance/payment' -import FinancePaymentForm from './FinancePaymentForm.vue' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpPriceTableColumnFormatter } from '@/utils' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 浠樻鍗曞垪琛� */ -defineOptions({ name: 'ErpPurchaseOrder' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<FinancePaymentVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - paymentTime: [], - supplierId: undefined, - creator: undefined, - financeUserId: undefined, - accountId: undefined, - status: undefined, - remark: undefined, - bizNo: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await FinancePaymentApi.getFinancePaymentPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await FinancePaymentApi.deleteFinancePayment(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ヤ粯娆惧崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await FinancePaymentApi.updateFinancePaymentStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await FinancePaymentApi.exportFinancePayment(queryParams) - download.excel(data, '浠樻鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<FinancePaymentVO[]>([]) -const handleSelectionChange = (rows: FinancePaymentVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇渚涘簲鍟嗐�佺敤鎴枫�佽处鎴� - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/finance/receipt/FinanceReceiptForm.vue b/src/views/erp/finance/receipt/FinanceReceiptForm.vue deleted file mode 100644 index 96826eb..0000000 --- a/src/views/erp/finance/receipt/FinanceReceiptForm.vue +++ /dev/null @@ -1,278 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鏀舵鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏀舵鏃堕棿" prop="receiptTime"> - <el-date-picker - v-model="formData.receiptTime" - type="date" - value-format="x" - placeholder="閫夋嫨鏀舵鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="formData.customerId" - clearable - filterable - placeholder="璇烽�夋嫨瀹㈡埛" - class="!w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璐㈠姟浜哄憳" prop="financeUserId"> - <el-select - v-model="formData.financeUserId" - clearable - filterable - placeholder="璇烽�夋嫨璐㈠姟浜哄憳" - class="!w-1/1" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="閲囪喘鍏ュ簱銆侀��璐у崟" name="item"> - <FinanceReceiptItemForm - ref="itemFormRef" - :customer-id="formData.customerId" - :items="formData.items" - :disabled="disabled" - /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鏀舵璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍚堣鏀舵" prop="totalPrice"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬閲戦" prop="discountPrice"> - <el-input-number - v-model="formData.discountPrice" - controls-position="right" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犻噾棰�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹為檯鏀舵"> - <el-input - disabled - v-model="formData.receiptPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { FinanceReceiptApi, FinanceReceiptVO } from '@/api/erp/finance/receipt' -import FinanceReceiptItemForm from './components/FinanceReceiptItemForm.vue' -import { erpPriceInputFormatter } from '@/utils' -import * as UserApi from '@/api/system/user' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' - -/** ERP 鏀舵鍗曡〃鍗� */ -defineOptions({ name: 'FinanceReceiptForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - accountId: undefined, - financeUserId: undefined, - receiptTime: undefined, - remark: undefined, - fileUrl: '', - totalPrice: 0, - discountPrice: 0, - receiptPrice: 0, - items: [], - no: undefined // 璁㈠崟鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - receiptTime: [{ required: true, message: '璁㈠崟鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalPrice = val.items.reduce((prev, curr) => prev + curr.receiptPrice, 0) - formData.value.totalPrice = totalPrice - formData.value.receiptPrice = totalPrice - val.discountPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await FinanceReceiptApi.getFinanceReceipt(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as FinanceReceiptVO - if (formType.value === 'create') { - await FinanceReceiptApi.createFinanceReceipt(data) - message.success(t('common.createSuccess')) - } else { - await FinanceReceiptApi.updateFinanceReceipt(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - accountId: undefined, - financeUserId: undefined, - receiptTime: undefined, - remark: undefined, - fileUrl: undefined, - totalPrice: 0, - discountPrice: 0, - receiptPrice: 0, - items: [], - no: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/finance/receipt/components/FinanceReceiptItemForm.vue b/src/views/erp/finance/receipt/components/FinanceReceiptItemForm.vue deleted file mode 100644 index 1a48b41..0000000 --- a/src/views/erp/finance/receipt/components/FinanceReceiptItemForm.vue +++ /dev/null @@ -1,176 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="閿�鍞崟鎹紪鍙�" min-width="200"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.bizNo" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴斾粯閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="宸蹭粯閲戦" prop="receiptedPrice" fixed="right" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.receiptedPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏈鏀舵" prop="receiptPrice" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.receiptPrice`" class="mb-0px!"> - <el-input-number - v-model="row.receiptPrice" - controls-position="right" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleOpenSaleOut" round>+ 娣诲姞閿�鍞嚭搴撳崟</el-button> - <el-button @click="handleOpenSaleReturn" round>+ 娣诲姞閿�鍞��璐у崟</el-button> - </el-row> - - <!-- 鍙敹娆剧殑銆愰攢鍞嚭搴撳崟銆戝垪琛� --> - <SaleOutReceiptEnableList ref="saleOutReceiptEnableListRef" @success="handleAddSaleOut" /> - <!-- 鍙敹娆剧殑銆愰攢鍞嚭搴撳崟銆戝垪琛� --> - <SaleReturnRefundEnableList ref="saleReturnRefundEnableListRef" @success="handleAddSaleReturn" /> -</template> -<script setup lang="ts"> -import { ProductVO } from '@/api/erp/product/product' -import { erpPriceInputFormatter, getSumValue } from '@/utils' -import SaleOutReceiptEnableList from '@/views/erp/sale/out/components/SaleOutReceiptEnableList.vue' -import SaleReturnRefundEnableList from '@/views/erp/sale/return/components/SaleReturnRefundEnableList.vue' -import { SaleOutVO } from '@/api/erp/sale/out' -import { ErpBizType } from '@/utils/constants' -import { SaleReturnVO } from '@/api/erp/sale/return' - -const props = defineProps<{ - items: undefined - customerId: undefined - disabled: false -}>() -const message = useMessage() - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - receiptPrice: [{ required: true, message: '鏈鏀舵涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['totalPrice', 'receiptedPrice', 'receiptPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - return sums -} - -/** 鏂板銆愰攢鍞嚭搴撱�戞寜閽搷浣� */ -const saleOutReceiptEnableListRef = ref() -const handleOpenSaleOut = () => { - if (!props.customerId) { - message.error('璇烽�夋嫨瀹㈡埛') - return - } - saleOutReceiptEnableListRef.value.open(props.customerId) -} -const handleAddSaleOut = (rows: SaleOutVO[]) => { - rows.forEach((row) => { - formData.value.push({ - bizId: row.id, - bizType: ErpBizType.SALE_OUT, - bizNo: row.no, - totalPrice: row.totalPrice, - receiptedPrice: row.receiptPrice, - receiptPrice: row.totalPrice - row.receiptPrice - }) - }) -} - -/** 鏂板銆愰攢鍞��璐с�戞寜閽搷浣� */ -const saleReturnRefundEnableListRef = ref() -const handleOpenSaleReturn = () => { - if (!props.customerId) { - message.error('璇烽�夋嫨瀹㈡埛') - return - } - saleReturnRefundEnableListRef.value.open(props.customerId) -} -const handleAddSaleReturn = (rows: SaleReturnVO[]) => { - rows.forEach((row) => { - formData.value.push({ - bizId: row.id, - bizType: ErpBizType.SALE_RETURN, - bizNo: row.no, - totalPrice: -row.totalPrice, - receiptedPrice: -row.refundPrice, - receiptPrice: -row.totalPrice + row.refundPrice - }) - }) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) -</script> diff --git a/src/views/erp/finance/receipt/index.vue b/src/views/erp/finance/receipt/index.vue deleted file mode 100644 index 1c8f82f..0000000 --- a/src/views/erp/finance/receipt/index.vue +++ /dev/null @@ -1,394 +0,0 @@ -<template> - <doc-alert - title="銆愯储鍔°�戦噰璐粯娆俱�侀攢鍞敹娆�" - url="https://doc.iocoder.cn/sale/finance-payment-receipt/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鏀舵鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ユ敹娆惧崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鏀舵鏃堕棿" prop="receiptTime"> - <el-date-picker - v-model="queryParams.receiptTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涗緵搴斿晢" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璐㈠姟浜哄憳" prop="financeUserId"> - <el-select - v-model="queryParams.financeUserId" - clearable - filterable - placeholder="璇烽�夋嫨璐㈠姟浜哄憳" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鏀舵璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨鏀舵璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="閲囪喘鍗曞彿" prop="bizNo"> - <el-input - v-model="queryParams.bizNo" - placeholder="璇疯緭鍏ラ噰璐崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:finance-receipt:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:finance-receipt:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:finance-receipt:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鏀舵鍗曞彿" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="鏀舵鏃堕棿" - align="center" - prop="receiptTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column label="璐㈠姟浜哄憳" align="center" prop="financeUserName" /> - <el-table-column label="鏀舵璐︽埛" align="center" prop="accountName" /> - <el-table-column - label="鍚堣鏀舵" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="浼樻儬閲戦" - align="center" - prop="discountPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="瀹為檯鏀舵" - align="center" - prop="receiptPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:finance-receipt:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:finance-receipt:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:finance-receipt:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:finance-receipt:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:finance-receipt:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <FinanceReceiptForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { FinanceReceiptApi, FinanceReceiptVO } from '@/api/erp/finance/receipt' -import FinanceReceiptForm from './FinanceReceiptForm.vue' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpPriceTableColumnFormatter } from '@/utils' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 鏀舵鍗曞垪琛� */ -defineOptions({ name: 'ErpPurchaseOrder' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<FinanceReceiptVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - receiptTime: [], - supplierId: undefined, - creator: undefined, - financeUserId: undefined, - accountId: undefined, - status: undefined, - remark: undefined, - bizNo: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await FinanceReceiptApi.getFinanceReceiptPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await FinanceReceiptApi.deleteFinanceReceipt(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ユ敹娆惧崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await FinanceReceiptApi.updateFinanceReceiptStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await FinanceReceiptApi.exportFinanceReceipt(queryParams) - download.excel(data, '鏀舵鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<FinanceReceiptVO[]>([]) -const handleSelectionChange = (rows: FinanceReceiptVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇渚涘簲鍟嗐�佺敤鎴枫�佽处鎴� - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/home/components/SummaryCard.vue b/src/views/erp/home/components/SummaryCard.vue deleted file mode 100644 index 21a02e2..0000000 --- a/src/views/erp/home/components/SummaryCard.vue +++ /dev/null @@ -1,21 +0,0 @@ -<template> - <div class="flex flex-col gap-2 bg-[var(--el-bg-color-overlay)] p-6"> - <div class="flex items-center justify-between text-gray-500"> - <span>{{ title }}</span> - </div> - <div class="flex flex-row items-baseline justify-between"> - <CountTo prefix="锟�" :end-val="value" :decimals="2" :duration="500" class="text-3xl" /> - </div> - </div> -</template> -<script lang="ts" setup> -import { propTypes } from '@/utils/propTypes' - -/** 浠锋牸灞曠ず Card */ -defineOptions({ name: 'ErpSummaryCard' }) - -defineProps({ - title: propTypes.string.def('').isRequired, - value: propTypes.number.def(0).isRequired -}) -</script> diff --git a/src/views/erp/home/components/TimeSummaryChart.vue b/src/views/erp/home/components/TimeSummaryChart.vue deleted file mode 100644 index 127fa87..0000000 --- a/src/views/erp/home/components/TimeSummaryChart.vue +++ /dev/null @@ -1,86 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <CardTitle :title="props.title" /> - </template> - <!-- 鎶樼嚎鍥� --> - <Echart :height="300" :options="lineChartOptions" /> - </el-card> -</template> -<script lang="ts" setup> -import { EChartsOption } from 'echarts' -import { formatDate } from '@/utils/formatTime' -import { CardTitle } from '@/components/Card' -import { propTypes } from '@/utils/propTypes' - -/** 浼氬憳鐢ㄦ埛缁熻鍗$墖 */ -defineOptions({ name: 'MemberStatisticsCard' }) - -const props = defineProps({ - title: propTypes.string.def('').isRequired, - value: propTypes.object.isRequired -}) - -/** 鎶樼嚎鍥鹃厤缃� */ -const lineChartOptions = reactive<EChartsOption>({ - dataset: { - dimensions: ['time', 'price'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - top: 80, - containLabel: true - }, - legend: { - top: 50 - }, - series: [{ name: '閲戦', type: 'line', smooth: true, areaStyle: {} }], - toolbox: { - feature: { - // 鏁版嵁鍖哄煙缂╂斁 - dataZoom: { - yAxisIndex: false // Y杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: props.title } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross' - }, - padding: [5, 10] - }, - xAxis: { - type: 'category', - boundaryGap: false, - axisTick: { - show: false - } - }, - yAxis: { - axisTick: { - show: false - } - } -}) as EChartsOption - -watch( - () => props.value, - (val) => { - if (!val) { - return - } - // 鏇存柊 Echarts 鏁版嵁 - if (lineChartOptions.dataset && lineChartOptions.dataset['source']) { - lineChartOptions.dataset['source'] = val - } - } -) -</script> diff --git a/src/views/erp/home/index.vue b/src/views/erp/home/index.vue deleted file mode 100644 index e399f9a..0000000 --- a/src/views/erp/home/index.vue +++ /dev/null @@ -1,93 +0,0 @@ -<template> - <doc-alert title="ERP 鎵嬪唽锛堝姛鑳藉紑鍚級" url="https://doc.iocoder.cn/erp/build/" /> - - <div class="flex flex-col"> - <!-- 閿�鍞�/閲囪喘鐨勫叏灞�缁熻 --> - <el-row :gutter="16" class="row"> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="浠婃棩閿�鍞�" :value="saleSummary?.todayPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="鏄ㄦ棩閿�鍞�" :value="saleSummary?.yesterdayPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="浠婃棩閲囪喘" :value="purchaseSummary?.todayPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="鏄ㄦ棩閲囪喘" :value="purchaseSummary?.yesterdayPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="鏈湀閿�鍞�" :value="saleSummary?.monthPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="浠婂勾閿�鍞�" :value="saleSummary?.yearPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="鏈湀閲囪喘" :value="purchaseSummary?.monthPrice" /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <SummaryCard title="浠婂勾閲囪喘" :value="purchaseSummary?.yearPrice" /> - </el-col> - </el-row> - <!-- 閿�鍞�/閲囪喘鐨勬椂娈电粺璁� --> - <el-row :gutter="16" class="row"> - <!-- 閿�鍞粺璁� --> - <el-col :md="12" :sm="12" :xs="24" :loading="loading"> - <TimeSummaryChart title="閿�鍞粺璁�" :value="saleTimeSummaryList" /> - </el-col> - <!-- 閲囪喘缁熻 --> - <el-col :md="12" :sm="12" :xs="24" :loading="loading"> - <TimeSummaryChart title="閲囪喘缁熻" :value="purchaseTimeSummaryList" /> - </el-col> - </el-row> - </div> -</template> -<script lang="ts" setup> -import SummaryCard from './components/SummaryCard.vue' -import TimeSummaryChart from './components/TimeSummaryChart.vue' -import { - ErpSaleSummaryRespVO, - ErpSaleTimeSummaryRespVO, - SaleStatisticsApi -} from '@/api/erp/statistics/sale' -import { - ErpPurchaseSummaryRespVO, - ErpPurchaseTimeSummaryRespVO, - PurchaseStatisticsApi -} from '@/api/erp/statistics/purchase' - -/** 鍟嗗煄棣栭〉 */ -defineOptions({ name: 'ErpHome' }) - -const loading = ref(true) // 鍔犺浇涓� - -/** 鑾峰緱閿�鍞粺璁� */ -const saleSummary = ref<ErpSaleSummaryRespVO>() // 閿�鍞鍐电粺璁� -const saleTimeSummaryList = ref<ErpSaleTimeSummaryRespVO[]>() // 閿�鍞椂娈电粺璁� -const getSaleSummary = async () => { - saleSummary.value = await SaleStatisticsApi.getSaleSummary() - saleTimeSummaryList.value = await SaleStatisticsApi.getSaleTimeSummary() -} - -/** 鑾峰緱閲囪喘缁熻 */ -const purchaseSummary = ref<ErpPurchaseSummaryRespVO>() // 閲囪喘姒傚喌缁熻 -const purchaseTimeSummaryList = ref<ErpPurchaseTimeSummaryRespVO[]>() // 閲囪喘鏃舵缁熻 -const getPurchaseSummary = async () => { - purchaseSummary.value = await PurchaseStatisticsApi.getPurchaseSummary() - purchaseTimeSummaryList.value = await PurchaseStatisticsApi.getPurchaseTimeSummary() -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - loading.value = true - await Promise.all([getSaleSummary(), getPurchaseSummary()]) - loading.value = false -}) -</script> -<style lang="scss" scoped> -.row { - .el-col { - margin-bottom: 1rem; - } -} -</style> diff --git a/src/views/erp/product/category/ProductCategoryForm.vue b/src/views/erp/product/category/ProductCategoryForm.vue deleted file mode 100644 index cef420c..0000000 --- a/src/views/erp/product/category/ProductCategoryForm.vue +++ /dev/null @@ -1,145 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="涓婄骇缂栧彿" prop="parentId"> - <el-tree-select - v-model="formData.parentId" - :data="productCategoryTree" - :props="defaultProps" - check-strictly - default-expand-all - placeholder="璇烽�夋嫨涓婄骇缂栧彿" - /> - </el-form-item> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="缂栫爜" prop="code"> - <el-input v-model="formData.code" placeholder="璇疯緭鍏ョ紪鐮�" /> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input v-model="formData.sort" placeholder="璇疯緭鍏ユ帓搴�" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category' -import { defaultProps, handleTree } from '@/utils/tree' -import { CommonStatusEnum } from '@/utils/constants' - -/** ERP 浜у搧鍒嗙被 琛ㄥ崟 */ -defineOptions({ name: 'ProductCategoryForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - parentId: undefined, - name: undefined, - code: undefined, - sort: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - parentId: [{ required: true, message: '涓婄骇缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - code: [{ required: true, message: '缂栫爜涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const productCategoryTree = ref() // 鏍戝舰缁撴瀯 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductCategoryApi.getProductCategory(id) - } finally { - formLoading.value = false - } - } - await getProductCategoryTree() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProductCategoryVO - if (formType.value === 'create') { - await ProductCategoryApi.createProductCategory(data) - message.success(t('common.createSuccess')) - } else { - await ProductCategoryApi.updateProductCategory(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - parentId: undefined, - name: undefined, - code: undefined, - sort: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} - -/** 鑾峰緱浜у搧鍒嗙被鏍� */ -const getProductCategoryTree = async () => { - productCategoryTree.value = [] - const data = await ProductCategoryApi.getProductCategoryList() - const root: Tree = { id: 0, name: '椤剁骇浜у搧鍒嗙被', children: [] } - root.children = handleTree(data, 'id', 'parentId') - productCategoryTree.value.push(root) -} -</script> diff --git a/src/views/erp/product/category/index.vue b/src/views/erp/product/category/index.vue deleted file mode 100644 index 281835d..0000000 --- a/src/views/erp/product/category/index.vue +++ /dev/null @@ -1,218 +0,0 @@ -<template> - <doc-alert title="銆愪骇鍝併�戜骇鍝佷俊鎭�佸垎绫汇�佸崟浣�" url="https://doc.iocoder.cn/erp/product/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍒嗙被鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ垎绫诲悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨寮�鍚姸鎬�" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:product-category:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:product-category:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button type="danger" plain @click="toggleExpandAll"> - <Icon icon="ep:sort" class="mr-5px" /> 灞曞紑/鎶樺彔 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - row-key="id" - :default-expand-all="isExpandAll" - v-if="refreshTable" - > - <el-table-column label="缂栫爜" align="center" prop="code" /> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:product-category:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:product-category:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductCategoryForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { handleTree } from '@/utils/tree' -import download from '@/utils/download' -import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category' -import ProductCategoryForm from './ProductCategoryForm.vue' - -/** ERP 浜у搧鍒嗙被 鍒楄〃 */ -defineOptions({ name: 'ErpProductCategory' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ProductCategoryVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - name: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductCategoryApi.getProductCategoryList(queryParams) - list.value = handleTree(data, 'id', 'parentId') - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductCategoryApi.deleteProductCategory(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ProductCategoryApi.exportProductCategory(queryParams) - download.excel(data, '浜у搧鍒嗙被.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 灞曞紑/鎶樺彔鎿嶄綔 */ -const isExpandAll = ref(true) // 鏄惁灞曞紑锛岄粯璁ゅ叏閮ㄥ睍寮� -const refreshTable = ref(true) // 閲嶆柊娓叉煋琛ㄦ牸鐘舵�� -const toggleExpandAll = async () => { - refreshTable.value = false - isExpandAll.value = !isExpandAll.value - await nextTick() - refreshTable.value = true -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/erp/product/product/ProductForm.vue b/src/views/erp/product/product/ProductForm.vue deleted file mode 100644 index 3f9de0a..0000000 --- a/src/views/erp/product/product/ProductForm.vue +++ /dev/null @@ -1,242 +0,0 @@ -<!-- ERP 浜у搧鐨勬柊澧�/淇敼 --> -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-row :gutter="20"> - <el-col :span="12"> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏉$爜" prop="barCode"> - <el-input v-model="formData.barCode" placeholder="璇疯緭鍏ユ潯鐮�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍒嗙被" prop="categoryId"> - <el-tree-select - v-model="formData.categoryId" - :data="categoryList" - :props="defaultProps" - check-strictly - default-expand-all - placeholder="璇烽�夋嫨鍒嗙被" - class="w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鍗曚綅" prop="unitId"> - <el-select v-model="formData.unitId" clearable placeholder="璇烽�夋嫨鍗曚綅" class="w-1/1"> - <el-option - v-for="unit in unitList" - :key="unit.id" - :label="unit.name" - :value="unit.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="瑙勬牸" prop="standard"> - <el-input v-model="formData.standard" placeholder="璇疯緭鍏ヨ鏍�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="淇濊川鏈熷ぉ鏁�" prop="expiryDay"> - <el-input-number - v-model="formData.expiryDay" - placeholder="璇疯緭鍏ヤ繚璐ㄦ湡澶╂暟" - :min="0" - :precision="0" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閲嶉噺锛坘g锛�" prop="weight"> - <el-input-number - v-model="formData.weight" - placeholder="璇疯緭鍏ラ噸閲忥紙kg锛�" - :min="0" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閲囪喘浠锋牸" prop="purchasePrice"> - <el-input-number - v-model="formData.purchasePrice" - placeholder="璇疯緭鍏ラ噰璐环鏍硷紝鍗曚綅锛氬厓" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="閿�鍞环鏍�" prop="salePrice"> - <el-input-number - v-model="formData.salePrice" - placeholder="璇疯緭鍏ラ攢鍞环鏍硷紝鍗曚綅锛氬厓" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏈�浣庝环鏍�" prop="minPrice"> - <el-input-number - v-model="formData.minPrice" - placeholder="璇疯緭鍏ユ渶浣庝环鏍硷紝鍗曚綅锛氬厓" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category' -import { ProductUnitApi, ProductUnitVO } from '@/api/erp/product/unit' -import { CommonStatusEnum } from '@/utils/constants' -import { defaultProps, handleTree } from '@/utils/tree' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -/** ERP 浜у搧 琛ㄥ崟 */ -defineOptions({ name: 'ProductForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - barCode: undefined, - categoryId: undefined, - unitId: undefined, - status: undefined, - standard: undefined, - remark: undefined, - expiryDay: undefined, - weight: undefined, - purchasePrice: undefined, - salePrice: undefined, - minPrice: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '浜у搧鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - barCode: [{ required: true, message: '浜у搧鏉$爜涓嶈兘涓虹┖', trigger: 'blur' }], - categoryId: [{ required: true, message: '浜у搧鍒嗙被缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - unitId: [{ required: true, message: '鍗曚綅缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '浜у搧鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const categoryList = ref<ProductCategoryVO[]>([]) // 浜у搧鍒嗙被鍒楄〃 -const unitList = ref<ProductUnitVO[]>([]) // 浜у搧鍗曚綅鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductApi.getProduct(id) - } finally { - formLoading.value = false - } - } - // 浜у搧鍒嗙被 - const categoryData = await ProductCategoryApi.getProductCategorySimpleList() - categoryList.value = handleTree(categoryData, 'id', 'parentId') - // 浜у搧鍗曚綅 - unitList.value = await ProductUnitApi.getProductUnitSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProductVO - if (formType.value === 'create') { - await ProductApi.createProduct(data) - message.success(t('common.createSuccess')) - } else { - await ProductApi.updateProduct(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - barCode: undefined, - categoryId: undefined, - unitId: undefined, - status: CommonStatusEnum.ENABLE, - standard: undefined, - remark: undefined, - expiryDay: undefined, - weight: undefined, - purchasePrice: undefined, - salePrice: undefined, - minPrice: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/product/product/index.vue b/src/views/erp/product/product/index.vue deleted file mode 100644 index 4eeba1e..0000000 --- a/src/views/erp/product/product/index.vue +++ /dev/null @@ -1,224 +0,0 @@ -<!-- ERP 浜у搧鍒楄〃 --> -<template> - <doc-alert title="銆愪骇鍝併�戜骇鍝佷俊鎭�佸垎绫汇�佸崟浣�" url="https://doc.iocoder.cn/erp/product/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒嗙被" prop="categoryId"> - <el-tree-select - v-model="queryParams.categoryId" - :data="categoryList" - :props="defaultProps" - check-strictly - default-expand-all - placeholder="璇疯緭鍏ュ垎绫�" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:product:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:product:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鏉$爜" align="center" prop="barCode" /> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="瑙勬牸" align="center" prop="standard" /> - <el-table-column label="鍒嗙被" align="center" prop="categoryName" /> - <el-table-column label="鍗曚綅" align="center" prop="unitName" /> - <el-table-column - label="閲囪喘浠锋牸" - align="center" - prop="purchasePrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="閿�鍞环鏍�" - align="center" - prop="salePrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鏈�浣庝环鏍�" - align="center" - prop="minPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="110"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:product:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:product:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category' -import ProductForm from './ProductForm.vue' -import { DICT_TYPE } from '@/utils/dict' -import { defaultProps, handleTree } from '@/utils/tree' -import { erpPriceTableColumnFormatter } from '@/utils' - -/** ERP 浜у搧鍒楄〃 */ -defineOptions({ name: 'ErpProduct' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ProductVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - categoryId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const categoryList = ref<ProductCategoryVO[]>([]) // 浜у搧鍒嗙被鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductApi.getProductPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductApi.deleteProduct(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ProductApi.exportProduct(queryParams) - download.excel(data, '浜у搧.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 浜у搧鍒嗙被 - const categoryData = await ProductCategoryApi.getProductCategorySimpleList() - categoryList.value = handleTree(categoryData, 'id', 'parentId') -}) -</script> diff --git a/src/views/erp/product/unit/ProductUnitForm.vue b/src/views/erp/product/unit/ProductUnitForm.vue deleted file mode 100644 index ca14ff4..0000000 --- a/src/views/erp/product/unit/ProductUnitForm.vue +++ /dev/null @@ -1,108 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍗曚綅鍚嶅瓧" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ崟浣嶅悕瀛�" /> - </el-form-item> - <el-form-item label="鍗曚綅鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { ProductUnitApi } from '@/api/erp/product/unit' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' - -/** ERP 浜у搧鍗曚綅琛ㄥ崟 */ -defineOptions({ name: 'ProductUnitForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - status: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍗曚綅鍚嶅瓧涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鍗曚綅鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductUnitApi.getProductUnit(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ProductUnitApi.ProductUnitVO - if (formType.value === 'create') { - await ProductUnitApi.createProductUnit(data) - message.success(t('common.createSuccess')) - } else { - await ProductUnitApi.updateProductUnit(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/product/unit/index.vue b/src/views/erp/product/unit/index.vue deleted file mode 100644 index 04259ac..0000000 --- a/src/views/erp/product/unit/index.vue +++ /dev/null @@ -1,198 +0,0 @@ -<template> - <doc-alert title="銆愪骇鍝併�戜骇鍝佷俊鎭�佸垎绫汇�佸崟浣�" url="https://doc.iocoder.cn/erp/product/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍗曚綅鍚嶅瓧" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ崟浣嶅悕瀛�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍗曚綅鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨鍗曚綅鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:product-unit:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:product-unit:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍚嶅瓧" align="center" prop="name" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:product-unit:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:product-unit:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ProductUnitForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { ProductUnitApi, ProductUnitVO } from '@/api/erp/product/unit' -import ProductUnitForm from './ProductUnitForm.vue' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -/** ERP 浜у搧鍗曚綅鍒楄〃 */ -defineOptions({ name: 'ErpProductUnit' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<ProductUnitVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductUnitApi.getProductUnitPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductUnitApi.deleteProductUnit(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ProductUnitApi.exportProductUnit(queryParams) - download.excel(data, '浜у搧鍗曚綅.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/erp/purchase/in/PurchaseInForm.vue b/src/views/erp/purchase/in/PurchaseInForm.vue deleted file mode 100644 index c59d7df..0000000 --- a/src/views/erp/purchase/in/PurchaseInForm.vue +++ /dev/null @@ -1,325 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鍏ュ簱鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏ュ簱鏃堕棿" prop="inTime"> - <el-date-picker - v-model="formData.inTime" - type="date" - value-format="x" - placeholder="閫夋嫨鍏ュ簱鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input v-model="formData.orderNo" readonly> - <template #append> - <el-button @click="openPurchaseOrderInEnableList"> - <Icon icon="ep:search" /> 閫夋嫨 - </el-button> - </template> - </el-input> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="formData.supplierId" - clearable - filterable - disabled - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-1/1" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="鍏ュ簱浜у搧娓呭崟" name="item"> - <PurchaseInItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浠樻浼樻儬" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input - disabled - :model-value="formData.totalPrice - formData.otherPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏跺畠璐圭敤" prop="otherPrice"> - <el-input-number - v-model="formData.otherPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ュ叾瀹冭垂鐢�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="搴斾粯閲戦"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - - <!-- 鍙叆搴撶殑璁㈠崟鍒楄〃 --> - <PurchaseOrderInEnableList - ref="purchaseOrderInEnableListRef" - @success="handlePurchaseOrderChange" - /> -</template> -<script setup lang="ts"> -import { PurchaseInApi, PurchaseInVO } from '@/api/erp/purchase/in' -import PurchaseInItemForm from './components/PurchaseInItemForm.vue' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import PurchaseOrderInEnableList from '@/views/erp/purchase/order/components/PurchaseOrderInEnableList.vue' -import { PurchaseOrderVO } from '@/api/erp/purchase/order' -import * as UserApi from '@/api/system/user' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' - -/** ERP 閿�鍞叆搴撹〃鍗� */ -defineOptions({ name: 'PurchaseInForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - supplierId: undefined, - accountId: undefined, - inTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - orderNo: undefined, - items: [], - no: undefined // 鍏ュ簱鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - supplierId: [{ required: true, message: '渚涘簲鍟嗕笉鑳戒负绌�', trigger: 'blur' }], - inTime: [{ required: true, message: '鍏ュ簱鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - // 璁$畻 - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.discountPrice = discountPrice - formData.value.totalPrice = totalPrice - discountPrice + val.otherPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await PurchaseInApi.getPurchaseIn(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇渚涘簲鍟嗗垪琛� - supplierList.value = await SupplierApi.getSupplierSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎵撳紑銆愬彲鍏ュ簱鐨勮鍗曞垪琛ㄣ�戝脊绐� */ -const purchaseOrderInEnableListRef = ref() // 鍙叆搴撶殑璁㈠崟鍒楄〃 Ref -const openPurchaseOrderInEnableList = () => { - purchaseOrderInEnableListRef.value.open() -} - -const handlePurchaseOrderChange = (order: PurchaseOrderVO) => { - // 灏嗚鍗曡缃埌鍏ュ簱鍗� - formData.value.orderId = order.id - formData.value.orderNo = order.no - formData.value.supplierId = order.supplierId - formData.value.accountId = order.accountId - formData.value.discountPercent = order.discountPercent - formData.value.remark = order.remark - formData.value.fileUrl = order.fileUrl - // 灏嗚鍗曢」璁剧疆鍒板叆搴撳崟椤� - order.items.forEach((item) => { - item.totalCount = item.count - item.count = item.totalCount - item.inCount - item.orderItemId = item.id - item.id = undefined - }) - formData.value.items = order.items.filter((item) => item.count > 0) -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as PurchaseInVO - if (formType.value === 'create') { - await PurchaseInApi.createPurchaseIn(data) - message.success(t('common.createSuccess')) - } else { - await PurchaseInApi.updatePurchaseIn(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - supplierId: undefined, - accountId: undefined, - inTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/purchase/in/components/PurchaseInItemForm.vue b/src/views/erp/purchase/in/components/PurchaseInItemForm.vue deleted file mode 100644 index 64377bc..0000000 --- a/src/views/erp/purchase/in/components/PurchaseInItemForm.vue +++ /dev/null @@ -1,300 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="鍘熸暟閲�" - fixed="right" - min-width="80" - v-if="formData[0]?.totalCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.totalCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸插叆搴�" - fixed="right" - min-width="80" - v-if="formData[0]?.inCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.inCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> - 鈥� - </el-button> - </template> - </el-table-column> - </el-table> - </el-form> -</template> -<script setup lang="ts"> -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃叆搴撻」 */ -watch( - () => props.items, - async (val) => { - val.forEach((item) => { - if (item.warehouseId == null) { - item.warehouseId = defaultWarehouse.value?.id - } - if (item.stockCount === null && item.warehouseId != null) { - setStockCount(item) - } - }) - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) -}) -</script> diff --git a/src/views/erp/purchase/in/components/PurchaseInPaymentEnableList.vue b/src/views/erp/purchase/in/components/PurchaseInPaymentEnableList.vue deleted file mode 100644 index afaa644..0000000 --- a/src/views/erp/purchase/in/components/PurchaseInPaymentEnableList.vue +++ /dev/null @@ -1,199 +0,0 @@ -<!-- 鍙粯娆剧殑閲囪喘鍏ュ簱鍗曞垪琛� --> -<template> - <Dialog - title="閫夋嫨閲囪喘鍏ュ簱锛堜粎灞曠ず鍙粯娆撅級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍏ュ簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏ュ簱鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.inTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍏ュ簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="鍏ュ簱鏃堕棿" - align="center" - prop="inTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="搴斾粯閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸蹭粯閲戦" - align="center" - prop="paymentPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈粯閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.paymentPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.paymentPrice) }} - </el-tag> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { PurchaseInApi, PurchaseInVO } from '@/api/erp/purchase/in' - -defineOptions({ name: 'PurchaseInPaymentEnableList' }) - -const list = ref<PurchaseInVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - inTime: [], - paymentEnable: true, - supplierId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<PurchaseInVO[]>([]) -const handleSelectionChange = (rows: PurchaseInVO[]) => { - selectionList.value = rows -} - -/** 鎵撳紑寮圭獥 */ -const open = async (supplierId: number) => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙叆搴撶殑璁㈠崟鍒楄〃 - queryParams.supplierId = supplierId - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: PurchaseInVO[]): void -}>() -const submitForm = () => { - try { - emits('success', selectionList.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseInApi.getPurchaseInPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - selectionList.value = [] - getList() -} -</script> diff --git a/src/views/erp/purchase/in/index.vue b/src/views/erp/purchase/in/index.vue deleted file mode 100644 index ce8ecee..0000000 --- a/src/views/erp/purchase/in/index.vue +++ /dev/null @@ -1,443 +0,0 @@ -<template> - <doc-alert title="銆愰噰璐�戦噰璐鍗曘�佸叆搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/purchase/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍏ュ簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏ュ簱鏃堕棿" prop="inTime"> - <el-date-picker - v-model="queryParams.inTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涗緵搴斿晢" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input - v-model="queryParams.orderNo" - placeholder="璇疯緭鍏ュ叧鑱旇鍗�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠樻鐘舵��" prop="paymentStatus"> - <el-select - v-model="queryParams.paymentStatus" - placeholder="璇烽�夋嫨鏈夋鐘舵��" - clearable - class="!w-240px" - > - <el-option label="鏈粯娆�" value="0" /> - <el-option label="閮ㄥ垎浠樻" value="1" /> - <el-option label="鍏ㄩ儴浠樻" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="瀹℃牳鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨瀹℃牳鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:purchase-in:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:purchase-in:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:purchase-in:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍏ュ簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="鍏ュ簱鏃堕棿" - align="center" - prop="inTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="搴斾粯閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸蹭粯閲戦" - align="center" - prop="paymentPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈粯閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.paymentPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.paymentPrice) }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="瀹℃牳鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:purchase-in:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:purchase-in:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:purchase-in:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:purchase-in:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:purchase-in:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <PurchaseInForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { PurchaseInApi, PurchaseInVO } from '@/api/erp/purchase/in' -import PurchaseInForm from './PurchaseInForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { - erpCountTableColumnFormatter, - erpPriceInputFormatter, - erpPriceTableColumnFormatter -} from '@/utils' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' - -/** ERP 閿�鍞叆搴撳垪琛� */ -defineOptions({ name: 'ErpPurchaseIn' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<PurchaseInVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - supplierId: undefined, - productId: undefined, - warehouseId: undefined, - inTime: [], - orderNo: undefined, - paymentStatus: undefined, - accountId: undefined, - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseInApi.getPurchaseInPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await PurchaseInApi.deletePurchaseIn(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ュ叆搴撳悧锛焋) - // 鍙戣捣瀹℃壒 - await PurchaseInApi.updatePurchaseInStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await PurchaseInApi.exportPurchaseIn(queryParams) - download.excel(data, '閿�鍞叆搴�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<PurchaseInVO[]>([]) -const handleSelectionChange = (rows: PurchaseInVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佷緵搴斿晢 - productList.value = await ProductApi.getProductSimpleList() - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/purchase/order/PurchaseOrderForm.vue b/src/views/erp/purchase/order/PurchaseOrderForm.vue deleted file mode 100644 index a7a6eec..0000000 --- a/src/views/erp/purchase/order/PurchaseOrderForm.vue +++ /dev/null @@ -1,269 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="formData.orderTime" - type="date" - value-format="x" - placeholder="閫夋嫨璁㈠崟鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="formData.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-1/1" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="璁㈠崟浜у搧娓呭崟" name="item"> - <PurchaseOrderItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浠樻浼樻儬" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏀粯璁㈤噾" prop="depositPrice"> - <el-input-number - v-model="formData.depositPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ユ敮浠樿閲�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { PurchaseOrderApi, PurchaseOrderVO } from '@/api/erp/purchase/order' -import PurchaseOrderItemForm from './components/PurchaseOrderItemForm.vue' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import * as UserApi from '@/api/system/user' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 閿�鍞鍗曡〃鍗� */ -defineOptions({ name: 'PurchaseOrderForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - supplierId: undefined, - accountId: undefined, - orderTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - depositPrice: 0, - items: [], - no: undefined // 璁㈠崟鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - supplierId: [{ required: true, message: '渚涘簲鍟嗕笉鑳戒负绌�', trigger: 'blur' }], - orderTime: [{ required: true, message: '璁㈠崟鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.discountPrice = discountPrice - formData.value.totalPrice = totalPrice - discountPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await PurchaseOrderApi.getPurchaseOrder(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇渚涘簲鍟嗗垪琛� - supplierList.value = await SupplierApi.getSupplierSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as PurchaseOrderVO - if (formType.value === 'create') { - await PurchaseOrderApi.createPurchaseOrder(data) - message.success(t('common.createSuccess')) - } else { - await PurchaseOrderApi.updatePurchaseOrder(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - supplierId: undefined, - accountId: undefined, - orderTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - depositPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/purchase/order/components/PurchaseOrderInEnableList.vue b/src/views/erp/purchase/order/components/PurchaseOrderInEnableList.vue deleted file mode 100644 index e10694a..0000000 --- a/src/views/erp/purchase/order/components/PurchaseOrderInEnableList.vue +++ /dev/null @@ -1,205 +0,0 @@ -<!-- 鍙叆搴撶殑璁㈠崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閲囪喘璁㈠崟锛堜粎灞曠ず鍙叆搴擄級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" width="65"> - <template #default="scope"> - <el-radio - :label="scope.row.id" - v-model="currentRowValue" - @change="handleCurrentChange(scope.row)" - > - - </el-radio> - </template> - </el-table-column> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍏ュ簱鏁伴噺" - align="center" - prop="inCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!currentRow" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { PurchaseOrderApi, PurchaseOrderVO } from '@/api/erp/purchase/order' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' - -defineOptions({ name: 'ErpPurchaseOrderOutEnableList' }) - -const list = ref<PurchaseOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - orderTime: [], - inEnable: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑琛� */ -const currentRowValue = ref(undefined) // 閫変腑琛岀殑 value -const currentRow = ref(undefined) // 閫変腑琛� -const handleCurrentChange = (row) => { - currentRow.value = row -} - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙叆搴撶殑璁㈠崟鍒楄〃 - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: PurchaseOrderVO): void -}>() -const submitForm = () => { - try { - emits('success', currentRow.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseOrderApi.getPurchaseOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - currentRowValue.value = undefined - currentRow.value = undefined - getList() -} -</script> diff --git a/src/views/erp/purchase/order/components/PurchaseOrderItemForm.vue b/src/views/erp/purchase/order/components/PurchaseOrderItemForm.vue deleted file mode 100644 index 265193e..0000000 --- a/src/views/erp/purchase/order/components/PurchaseOrderItemForm.vue +++ /dev/null @@ -1,271 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞閲囪喘浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃叆搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.purchasePrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/purchase/order/components/PurchaseOrderReturnEnableList.vue b/src/views/erp/purchase/order/components/PurchaseOrderReturnEnableList.vue deleted file mode 100644 index cac2bbc..0000000 --- a/src/views/erp/purchase/order/components/PurchaseOrderReturnEnableList.vue +++ /dev/null @@ -1,212 +0,0 @@ -<!-- 鍙��璐х殑璁㈠崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閲囪喘璁㈠崟锛堜粎灞曠ず鍙��璐э級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" width="65"> - <template #default="scope"> - <el-radio - :label="scope.row.id" - v-model="currentRowValue" - @change="handleCurrentChange(scope.row)" - > - - </el-radio> - </template> - </el-table-column> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍏ュ簱鏁伴噺" - align="center" - prop="inCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閫�璐ф暟閲�" - align="center" - prop="returnCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!currentRow" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { PurchaseOrderApi, PurchaseOrderVO } from '@/api/erp/purchase/order' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' - -defineOptions({ name: 'PurchaseOrderReturnEnableList' }) - -const list = ref<PurchaseOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - orderTime: [], - returnEnable: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑琛� */ -const currentRowValue = ref(undefined) // 閫変腑琛岀殑 value -const currentRow = ref(undefined) // 閫変腑琛� -const handleCurrentChange = (row) => { - currentRow.value = row -} - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙��璐х殑璁㈠崟鍒楄〃 - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: PurchaseOrderVO): void -}>() -const submitForm = () => { - try { - emits('success', currentRow.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseOrderApi.getPurchaseOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - currentRowValue.value = undefined - currentRow.value = undefined - getList() -} -</script> diff --git a/src/views/erp/purchase/order/index.vue b/src/views/erp/purchase/order/index.vue deleted file mode 100644 index f179fa9..0000000 --- a/src/views/erp/purchase/order/index.vue +++ /dev/null @@ -1,407 +0,0 @@ -<template> - <doc-alert title="銆愰噰璐�戦噰璐鍗曘�佸叆搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/purchase/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涗緵搴斿晢" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍏ュ簱鏁伴噺" prop="inStatus"> - <el-select - v-model="queryParams.inStatus" - placeholder="璇烽�夋嫨鍏ュ簱鏁伴噺" - clearable - class="!w-240px" - > - <el-option label="鏈叆搴�" value="0" /> - <el-option label="閮ㄥ垎鍏ュ簱" value="1" /> - <el-option label="鍏ㄩ儴鍏ュ簱" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф暟閲�" prop="returnStatus"> - <el-select - v-model="queryParams.returnStatus" - placeholder="璇烽�夋嫨閫�璐ф暟閲�" - clearable - class="!w-240px" - > - <el-option label="鏈��璐�" value="0" /> - <el-option label="閮ㄥ垎閫�璐�" value="1" /> - <el-option label="鍏ㄩ儴閫�璐�" value="2" /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:purchase-order:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:purchase-order:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:purchase-order:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍏ュ簱鏁伴噺" - align="center" - prop="inCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閫�璐ф暟閲�" - align="center" - prop="returnCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鏀粯璁㈤噾" - align="center" - prop="depositPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:purchase-order:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:purchase-order:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:purchase-order:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:purchase-order:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:purchase-order:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <PurchaseOrderForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { PurchaseOrderApi, PurchaseOrderVO } from '@/api/erp/purchase/order' -import PurchaseOrderForm from './PurchaseOrderForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' - -/** ERP 閿�鍞鍗曞垪琛� */ -defineOptions({ name: 'ErpPurchaseOrder' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<PurchaseOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - supplierId: undefined, - productId: undefined, - orderTime: [], - status: undefined, - remark: undefined, - creator: undefined, - inStatus: undefined, - returnStatus: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseOrderApi.getPurchaseOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await PurchaseOrderApi.deletePurchaseOrder(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ヨ鍗曞悧锛焋) - // 鍙戣捣瀹℃壒 - await PurchaseOrderApi.updatePurchaseOrderStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await PurchaseOrderApi.exportPurchaseOrder(queryParams) - download.excel(data, '閿�鍞鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<PurchaseOrderVO[]>([]) -const handleSelectionChange = (rows: PurchaseOrderVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佷緵搴斿晢 - productList.value = await ProductApi.getProductSimpleList() - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/purchase/return/PurchaseReturnForm.vue b/src/views/erp/purchase/return/PurchaseReturnForm.vue deleted file mode 100644 index e37fa09..0000000 --- a/src/views/erp/purchase/return/PurchaseReturnForm.vue +++ /dev/null @@ -1,328 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閫�璐ф椂闂�" prop="returnTime"> - <el-date-picker - v-model="formData.returnTime" - type="date" - value-format="x" - placeholder="閫夋嫨閫�璐ф椂闂�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input v-model="formData.orderNo" readonly> - <template #append> - <el-button @click="openPurchaseOrderReturnEnableList"> - <Icon icon="ep:search" /> 閫夋嫨 - </el-button> - </template> - </el-input> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="formData.supplierId" - clearable - filterable - disabled - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-1/1" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="閫�璐т骇鍝佹竻鍗�" name="item"> - <PurchaseReturnItemForm - ref="itemFormRef" - :items="formData.items" - :disabled="disabled" - /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閫�娆句紭鎯�" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input - disabled - :model-value="formData.totalPrice - formData.otherPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏跺畠璐圭敤" prop="otherPrice"> - <el-input-number - v-model="formData.otherPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ュ叾瀹冭垂鐢�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="搴旈��閲戦" prop="totalPrice"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - - <!-- 鍙��璐х殑璁㈠崟鍒楄〃 --> - <PurchaseOrderReturnEnableList - ref="purchaseOrderReturnEnableListRef" - @success="handlePurchaseOrderChange" - /> -</template> -<script setup lang="ts"> -import { PurchaseReturnApi, PurchaseReturnVO } from '@/api/erp/purchase/return' -import PurchaseReturnItemForm from './components/PurchaseReturnItemForm.vue' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import PurchaseOrderReturnEnableList from '@/views/erp/purchase/order/components/PurchaseOrderReturnEnableList.vue' -import { PurchaseOrderVO } from '@/api/erp/purchase/order' -import * as UserApi from '@/api/system/user' - -/** ERP 閲囪喘閫�璐ц〃鍗� */ -defineOptions({ name: 'PurchaseReturnForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - supplierId: undefined, - accountId: undefined, - returnTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - orderNo: undefined, - items: [], - no: undefined // 閫�璐у崟鍙凤紝鍚庣杩斿洖 -}) -const formRules = reactive({ - supplierId: [{ required: true, message: '渚涘簲鍟嗕笉鑳戒负绌�', trigger: 'blur' }], - returnTime: [{ required: true, message: '閫�璐ф椂闂翠笉鑳戒负绌�', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - // 璁$畻 - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.discountPrice = discountPrice - formData.value.totalPrice = totalPrice - discountPrice + val.otherPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await PurchaseReturnApi.getPurchaseReturn(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇渚涘簲鍟嗗垪琛� - supplierList.value = await SupplierApi.getSupplierSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎵撳紑銆愬彲閫�璐х殑璁㈠崟鍒楄〃銆戝脊绐� */ -const purchaseOrderReturnEnableListRef = ref() // 鍙��璐х殑璁㈠崟鍒楄〃 Ref -const openPurchaseOrderReturnEnableList = () => { - purchaseOrderReturnEnableListRef.value.open() -} - -const handlePurchaseOrderChange = (order: PurchaseOrderVO) => { - // 灏嗚鍗曡缃埌閫�璐у崟 - formData.value.orderId = order.id - formData.value.orderNo = order.no - formData.value.supplierId = order.supplierId - formData.value.accountId = order.accountId - formData.value.discountPercent = order.discountPercent - formData.value.remark = order.remark - formData.value.fileUrl = order.fileUrl - // 灏嗚鍗曢」璁剧疆鍒伴��璐у崟椤� - order.items.forEach((item) => { - item.count = item.inCount - item.returnCount - item.orderItemId = item.id - item.id = undefined - }) - formData.value.items = order.items.filter((item) => item.count > 0) -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as PurchaseReturnVO - if (formType.value === 'create') { - await PurchaseReturnApi.createPurchaseReturn(data) - message.success(t('common.createSuccess')) - } else { - await PurchaseReturnApi.updatePurchaseReturn(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - supplierId: undefined, - accountId: undefined, - returnTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/purchase/return/components/PurchaseReturnItemForm.vue b/src/views/erp/purchase/return/components/PurchaseReturnItemForm.vue deleted file mode 100644 index 2d3e8c5..0000000 --- a/src/views/erp/purchase/return/components/PurchaseReturnItemForm.vue +++ /dev/null @@ -1,300 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸插嚭搴�" - fixed="right" - min-width="80" - v-if="formData[0]?.inCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.inCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸查��璐�" - fixed="right" - min-width="80" - v-if="formData[0]?.returnCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.returnCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> - 鈥� - </el-button> - </template> - </el-table-column> - </el-table> - </el-form> -</template> -<script setup lang="ts"> -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - val.forEach((item) => { - if (item.warehouseId == null) { - item.warehouseId = defaultWarehouse.value?.id - } - if (item.stockCount === null && item.warehouseId != null) { - setStockCount(item) - } - }) - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) -}) -</script> diff --git a/src/views/erp/purchase/return/components/PurchaseReturnRefundEnableList.vue b/src/views/erp/purchase/return/components/PurchaseReturnRefundEnableList.vue deleted file mode 100644 index a95749e..0000000 --- a/src/views/erp/purchase/return/components/PurchaseReturnRefundEnableList.vue +++ /dev/null @@ -1,200 +0,0 @@ -<!-- 鍙��娆剧殑閲囪喘閫�璐у崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閲囪喘閫�璐э紙浠呭睍绀哄彲閫�娆撅級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ラ��璐у崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф椂闂�" prop="orderTime"> - <el-date-picker - v-model="queryParams.returnTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="閫�璐у崟鍙�" align="center" prop="no" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="閫�璐ф椂闂�" - align="center" - prop="returnTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="搴旈��閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸查��閲戦" - align="center" - prop="refundPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈��閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }} - </el-tag> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { PurchaseReturnApi, PurchaseReturnVO } from '@/api/erp/purchase/return' -import { SaleReturnVO } from '@/api/erp/sale/return' - -defineOptions({ name: 'PurchaseInPaymentEnableList' }) - -const list = ref<PurchaseReturnVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - returnTime: [], - refundEnable: true, - supplierId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleReturnVO[]>([]) -const handleSelectionChange = (rows: SaleReturnVO[]) => { - selectionList.value = rows -} - -/** 鎵撳紑寮圭獥 */ -const open = async (supplierId: number) => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍒楄〃 - queryParams.supplierId = supplierId - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: SaleReturnVO[]): void -}>() -const submitForm = () => { - try { - emits('success', selectionList.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseReturnApi.getPurchaseReturnPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - selectionList.value = [] - getList() -} -</script> diff --git a/src/views/erp/purchase/return/index.vue b/src/views/erp/purchase/return/index.vue deleted file mode 100644 index 545d18a..0000000 --- a/src/views/erp/purchase/return/index.vue +++ /dev/null @@ -1,443 +0,0 @@ -<template> - <doc-alert title="銆愰噰璐�戦噰璐鍗曘�佸叆搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/purchase/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ラ��璐у崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф椂闂�" prop="inTime"> - <el-date-picker - v-model="queryParams.inTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涗緵搴斿晢" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input - v-model="queryParams.orderNo" - placeholder="璇疯緭鍏ュ叧鑱旇鍗�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�娆剧姸鎬�" prop="refundStatus"> - <el-select - v-model="queryParams.refundStatus" - placeholder="璇烽�夋嫨閫�娆剧姸鎬�" - clearable - class="!w-240px" - > - <el-option label="鏈��娆�" value="0" /> - <el-option label="閮ㄥ垎閫�娆�" value="1" /> - <el-option label="鍏ㄩ儴閫�娆�" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="瀹℃牳鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨瀹℃牳鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:purchase-return:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:purchase-return:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:purchase-return:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="閫�璐у崟鍙�" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="閫�璐ф椂闂�" - align="center" - prop="returnTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="搴旈��閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸查��閲戦" - align="center" - prop="refundPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈��閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="瀹℃牳鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:purchase-return:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:purchase-return:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:purchase-return:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:purchase-return:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:purchase-return:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <PurchaseReturnForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { PurchaseReturnApi, PurchaseReturnVO } from '@/api/erp/purchase/return' -import PurchaseReturnForm from './PurchaseReturnForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { - erpCountTableColumnFormatter, - erpPriceInputFormatter, - erpPriceTableColumnFormatter -} from '@/utils' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 閲囪喘閫�璐у垪琛� */ -defineOptions({ name: 'ErpPurchaseReturn' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<PurchaseReturnVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - supplierId: undefined, - productId: undefined, - warehouseId: undefined, - returnTime: [], - orderNo: undefined, - accountId: undefined, - status: undefined, - refundStatus: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PurchaseReturnApi.getPurchaseReturnPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await PurchaseReturnApi.deletePurchaseReturn(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ラ��璐у悧锛焋) - // 鍙戣捣瀹℃壒 - await PurchaseReturnApi.updatePurchaseReturnStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await PurchaseReturnApi.exportPurchaseReturn(queryParams) - download.excel(data, '閲囪喘閫�璐�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<PurchaseReturnVO[]>([]) -const handleSelectionChange = (rows: PurchaseReturnVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佷緵搴斿晢 - productList.value = await ProductApi.getProductSimpleList() - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/purchase/supplier/SupplierForm.vue b/src/views/erp/purchase/supplier/SupplierForm.vue deleted file mode 100644 index d3c433c..0000000 --- a/src/views/erp/purchase/supplier/SupplierForm.vue +++ /dev/null @@ -1,210 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-row :gutter="20"> - <el-col :span="12"> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鑱旂郴浜�" prop="contact"> - <el-input v-model="formData.contact" placeholder="璇疯緭鍏ヨ仈绯讳汉" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎵嬫満鍙风爜" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鑱旂郴鐢佃瘽" prop="telephone"> - <el-input v-model="formData.telephone" placeholder="璇疯緭鍏ヨ仈绯荤數璇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鐢靛瓙閭" prop="email"> - <el-input v-model="formData.email" placeholder="璇疯緭鍏ョ數瀛愰偖绠�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浼犵湡" prop="fax"> - <el-input v-model="formData.fax" placeholder="璇疯緭鍏ヤ紶鐪�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number - v-model="formData.sort" - placeholder="璇疯緭鍏ユ帓搴�" - class="!w-1/1" - :precision="0" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绾崇◣浜鸿瘑鍒彿" prop="taxNo"> - <el-input v-model="formData.taxNo" placeholder="璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绋庣巼(%)" prop="taxPercent"> - <el-input-number - v-model="formData.taxPercent" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ョ◣鐜�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴疯" prop="bankName"> - <el-input v-model="formData.bankName" placeholder="璇疯緭鍏ュ紑鎴疯" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴疯处鍙�" prop="bankAccount"> - <el-input v-model="formData.bankAccount" placeholder="璇疯緭鍏ュ紑鎴疯处鍙�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴峰湴鍧�" prop="bankAddress"> - <el-input v-model="formData.bankAddress" placeholder="璇疯緭鍏ュ紑鎴峰湴鍧�" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { CommonStatusEnum } from '@/utils/constants' - -/** ERP 琛ㄥ崟 */ -defineOptions({ name: 'SupplierForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - contact: undefined, - mobile: undefined, - telephone: undefined, - email: undefined, - fax: undefined, - remark: undefined, - status: undefined, - sort: undefined, - taxNo: undefined, - taxPercent: undefined, - bankName: undefined, - bankAccount: undefined, - bankAddress: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SupplierApi.getSupplier(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as SupplierVO - if (formType.value === 'create') { - await SupplierApi.createSupplier(data) - message.success(t('common.createSuccess')) - } else { - await SupplierApi.updateSupplier(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - contact: undefined, - mobile: undefined, - telephone: undefined, - email: undefined, - fax: undefined, - remark: undefined, - status: CommonStatusEnum.ENABLE, - sort: undefined, - taxNo: undefined, - taxPercent: undefined, - bankName: undefined, - bankAccount: undefined, - bankAddress: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/purchase/supplier/index.vue b/src/views/erp/purchase/supplier/index.vue deleted file mode 100644 index 4d3a405..0000000 --- a/src/views/erp/purchase/supplier/index.vue +++ /dev/null @@ -1,201 +0,0 @@ -<template> - <doc-alert title="銆愰噰璐�戦噰璐鍗曘�佸叆搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/purchase/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎵嬫満鍙风爜" prop="mobile"> - <el-input - v-model="queryParams.mobile" - placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鑱旂郴鐢佃瘽" prop="telephone"> - <el-input - v-model="queryParams.telephone" - placeholder="璇疯緭鍏ヨ仈绯荤數璇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:supplier:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:supplier:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="鑱旂郴浜�" align="center" prop="contact" /> - <el-table-column label="鎵嬫満鍙风爜" align="center" prop="mobile" /> - <el-table-column label="鑱旂郴鐢佃瘽" align="center" prop="telephone" /> - <el-table-column label="鐢靛瓙閭" align="center" prop="email" /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:supplier:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:supplier:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SupplierForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import SupplierForm from './SupplierForm.vue' - -/** ERP 渚涘簲鍟� 鍒楄〃 */ -defineOptions({ name: 'ErpSupplier' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<SupplierVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - mobile: undefined, - telephone: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SupplierApi.getSupplierPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SupplierApi.deleteSupplier(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await SupplierApi.exportSupplier(queryParams) - download.excel(data, 'ERP 渚涘簲鍟�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/erp/sale/customer/CustomerForm.vue b/src/views/erp/sale/customer/CustomerForm.vue deleted file mode 100644 index da6e004..0000000 --- a/src/views/erp/sale/customer/CustomerForm.vue +++ /dev/null @@ -1,210 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-row :gutter="20"> - <el-col :span="12"> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鑱旂郴浜�" prop="contact"> - <el-input v-model="formData.contact" placeholder="璇疯緭鍏ヨ仈绯讳汉" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎵嬫満鍙风爜" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鑱旂郴鐢佃瘽" prop="telephone"> - <el-input v-model="formData.telephone" placeholder="璇疯緭鍏ヨ仈绯荤數璇�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鐢靛瓙閭" prop="email"> - <el-input v-model="formData.email" placeholder="璇疯緭鍏ョ數瀛愰偖绠�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浼犵湡" prop="fax"> - <el-input v-model="formData.fax" placeholder="璇疯緭鍏ヤ紶鐪�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number - v-model="formData.sort" - placeholder="璇疯緭鍏ユ帓搴�" - class="!w-1/1" - :precision="0" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绾崇◣浜鸿瘑鍒彿" prop="taxNo"> - <el-input v-model="formData.taxNo" placeholder="璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绋庣巼(%)" prop="taxPercent"> - <el-input-number - v-model="formData.taxPercent" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ョ◣鐜�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴疯" prop="bankName"> - <el-input v-model="formData.bankName" placeholder="璇疯緭鍏ュ紑鎴疯" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴疯处鍙�" prop="bankAccount"> - <el-input v-model="formData.bankAccount" placeholder="璇疯緭鍏ュ紑鎴疯处鍙�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="寮�鎴峰湴鍧�" prop="bankAddress"> - <el-input v-model="formData.bankAddress" placeholder="璇疯緭鍏ュ紑鎴峰湴鍧�" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { CommonStatusEnum } from '@/utils/constants' - -/** ERP 瀹㈡埛 琛ㄥ崟 */ -defineOptions({ name: 'CustomerForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - contact: undefined, - mobile: undefined, - telephone: undefined, - email: undefined, - fax: undefined, - remark: undefined, - status: undefined, - sort: undefined, - taxNo: undefined, - taxPercent: undefined, - bankName: undefined, - bankAccount: undefined, - bankAddress: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '瀹㈡埛鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await CustomerApi.getCustomer(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as CustomerVO - if (formType.value === 'create') { - await CustomerApi.createCustomer(data) - message.success(t('common.createSuccess')) - } else { - await CustomerApi.updateCustomer(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - contact: undefined, - mobile: undefined, - telephone: undefined, - email: undefined, - fax: undefined, - remark: undefined, - status: CommonStatusEnum.ENABLE, - sort: undefined, - taxNo: undefined, - taxPercent: undefined, - bankName: undefined, - bankAccount: undefined, - bankAddress: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/sale/customer/index.vue b/src/views/erp/sale/customer/index.vue deleted file mode 100644 index c79bbe8..0000000 --- a/src/views/erp/sale/customer/index.vue +++ /dev/null @@ -1,201 +0,0 @@ -<template> - <doc-alert title="銆愰攢鍞�戦攢鍞鍗曘�佸嚭搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/sale/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎵嬫満鍙风爜" prop="mobile"> - <el-input - v-model="queryParams.mobile" - placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鑱旂郴鐢佃瘽" prop="telephone"> - <el-input - v-model="queryParams.telephone" - placeholder="璇疯緭鍏ヨ仈绯荤數璇�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:customer:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:customer:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍚嶇О" align="center" prop="name" /> - <el-table-column label="鑱旂郴浜�" align="center" prop="contact" /> - <el-table-column label="鎵嬫満鍙风爜" align="center" prop="mobile" /> - <el-table-column label="鑱旂郴鐢佃瘽" align="center" prop="telephone" /> - <el-table-column label="鐢靛瓙閭" align="center" prop="email" /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:customer:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:customer:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CustomerForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import CustomerForm from './CustomerForm.vue' - -/** ERP 瀹㈡埛 鍒楄〃 */ -defineOptions({ name: 'ErpCustomer' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<CustomerVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - mobile: undefined, - telephone: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CustomerApi.getCustomerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await CustomerApi.deleteCustomer(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await CustomerApi.exportCustomer(queryParams) - download.excel(data, '瀹㈡埛.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/erp/sale/order/SaleOrderForm.vue b/src/views/erp/sale/order/SaleOrderForm.vue deleted file mode 100644 index 30b2b30..0000000 --- a/src/views/erp/sale/order/SaleOrderForm.vue +++ /dev/null @@ -1,289 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="formData.orderTime" - type="date" - value-format="x" - placeholder="閫夋嫨璁㈠崟鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="formData.customerId" - clearable - filterable - placeholder="璇烽�夋嫨瀹㈡埛" - class="!w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閿�鍞汉鍛�" prop="saleUserId"> - <el-select - v-model="formData.saleUserId" - clearable - filterable - placeholder="璇烽�夋嫨閿�鍞汉鍛�" - class="!w-1/1" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="璁㈠崟浜у搧娓呭崟" name="item"> - <SaleOrderItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏀舵浼樻儬" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏀跺彇璁㈤噾" prop="depositPrice"> - <el-input-number - v-model="formData.depositPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ユ敹鍙栬閲�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' -import SaleOrderItemForm from './components/SaleOrderItemForm.vue' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import * as UserApi from '@/api/system/user' - -/** ERP 閿�鍞鍗曡〃鍗� */ -defineOptions({ name: 'SaleOrderForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - orderTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - depositPrice: 0, - items: [], - no: undefined // 璁㈠崟鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - orderTime: [{ required: true, message: '璁㈠崟鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.discountPrice = discountPrice - formData.value.totalPrice = totalPrice - discountPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SaleOrderApi.getSaleOrder(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as SaleOrderVO - if (formType.value === 'create') { - await SaleOrderApi.createSaleOrder(data) - message.success(t('common.createSuccess')) - } else { - await SaleOrderApi.updateSaleOrder(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - orderTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - depositPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/sale/order/components/SaleOrderItemForm.vue b/src/views/erp/sale/order/components/SaleOrderItemForm.vue deleted file mode 100644 index 3a579d5..0000000 --- a/src/views/erp/sale/order/components/SaleOrderItemForm.vue +++ /dev/null @@ -1,271 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞閲囪喘浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.salePrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/sale/order/components/SaleOrderOutEnableList.vue b/src/views/erp/sale/order/components/SaleOrderOutEnableList.vue deleted file mode 100644 index 55de745..0000000 --- a/src/views/erp/sale/order/components/SaleOrderOutEnableList.vue +++ /dev/null @@ -1,206 +0,0 @@ -<!-- 鍙嚭搴撶殑璁㈠崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閿�鍞鍗曪紙浠呭睍绀哄彲鍑哄簱锛�" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" width="65"> - <template #default="scope"> - <el-radio - :label="scope.row.id" - v-model="currentRowValue" - @change="handleCurrentChange(scope.row)" - > - - </el-radio> - </template> - </el-table-column> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍑哄簱鏁伴噺" - align="center" - prop="outCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!currentRow" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' - -defineOptions({ name: 'ErpSaleOrderOutEnableList' }) - -const list = ref<SaleOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - orderTime: [], - outEnable: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑琛� */ -const currentRowValue = ref(undefined) // 閫変腑琛岀殑 value -const currentRow = ref(undefined) // 閫変腑琛� -const handleCurrentChange = (row) => { - currentRow.value = row -} - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙嚭搴撶殑璁㈠崟鍒楄〃 - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: SaleOrderVO): void -}>() -const submitForm = () => { - try { - emits('success', currentRow.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleOrderApi.getSaleOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - currentRowValue.value = undefined - currentRow.value = undefined - getList() -} -</script> diff --git a/src/views/erp/sale/order/components/SaleOrderReturnEnableList.vue b/src/views/erp/sale/order/components/SaleOrderReturnEnableList.vue deleted file mode 100644 index a93a997..0000000 --- a/src/views/erp/sale/order/components/SaleOrderReturnEnableList.vue +++ /dev/null @@ -1,212 +0,0 @@ -<!-- 鍙��璐х殑璁㈠崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閿�鍞鍗曪紙浠呭睍绀哄彲閫�璐э級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" width="65"> - <template #default="scope"> - <el-radio - :label="scope.row.id" - v-model="currentRowValue" - @change="handleCurrentChange(scope.row)" - > - - </el-radio> - </template> - </el-table-column> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍑哄簱鏁伴噺" - align="center" - prop="outCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閫�璐ф暟閲�" - align="center" - prop="returnCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!currentRow" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' - -defineOptions({ name: 'SaleOrderReturnEnableList' }) - -const list = ref<SaleOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - orderTime: [], - returnEnable: true -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑琛� */ -const currentRowValue = ref(undefined) // 閫変腑琛岀殑 value -const currentRow = ref(undefined) // 閫変腑琛� -const handleCurrentChange = (row) => { - currentRow.value = row -} - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙��璐х殑璁㈠崟鍒楄〃 - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: SaleOrderVO): void -}>() -const submitForm = () => { - try { - emits('success', currentRow.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleOrderApi.getSaleOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - currentRowValue.value = undefined - currentRow.value = undefined - getList() -} -</script> diff --git a/src/views/erp/sale/order/index.vue b/src/views/erp/sale/order/index.vue deleted file mode 100644 index deb03c0..0000000 --- a/src/views/erp/sale/order/index.vue +++ /dev/null @@ -1,407 +0,0 @@ -<template> - <doc-alert title="銆愰攢鍞�戦攢鍞鍗曘�佸嚭搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/sale/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璁㈠崟鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ鍗曞崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.orderTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘鎴�" - class="!w-240px" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍑哄簱鏁伴噺" prop="outStatus"> - <el-select - v-model="queryParams.outStatus" - placeholder="璇烽�夋嫨鍑哄簱鏁伴噺" - clearable - class="!w-240px" - > - <el-option label="鏈嚭搴�" value="0" /> - <el-option label="閮ㄥ垎鍑哄簱" value="1" /> - <el-option label="鍏ㄩ儴鍑哄簱" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф暟閲�" prop="returnStatus"> - <el-select - v-model="queryParams.returnStatus" - placeholder="璇烽�夋嫨閫�璐ф暟閲�" - clearable - class="!w-240px" - > - <el-option label="鏈��璐�" value="0" /> - <el-option label="閮ㄥ垎閫�璐�" value="1" /> - <el-option label="鍏ㄩ儴閫�璐�" value="2" /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:sale-order:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:sale-order:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:sale-order:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="璁㈠崟鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column - label="璁㈠崟鏃堕棿" - align="center" - prop="orderTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="鍑哄簱鏁伴噺" - align="center" - prop="outCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閫�璐ф暟閲�" - align="center" - prop="returnCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦鍚堣" - align="center" - prop="totalProductPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鍚◣閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鏀跺彇璁㈤噾" - align="center" - prop="depositPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:sale-order:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:sale-order:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:sale-order:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:sale-order:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:sale-order:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SaleOrderForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' -import SaleOrderForm from './SaleOrderForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' - -/** ERP 閿�鍞鍗曞垪琛� */ -defineOptions({ name: 'ErpSaleOrder' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<SaleOrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - customerId: undefined, - productId: undefined, - orderTime: [], - status: undefined, - remark: undefined, - creator: undefined, - outStatus: undefined, - returnStatus: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleOrderApi.getSaleOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SaleOrderApi.deleteSaleOrder(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ヨ鍗曞悧锛焋) - // 鍙戣捣瀹℃壒 - await SaleOrderApi.updateSaleOrderStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await SaleOrderApi.exportSaleOrder(queryParams) - download.excel(data, '閿�鍞鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleOrderVO[]>([]) -const handleSelectionChange = (rows: SaleOrderVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - customerList.value = await CustomerApi.getCustomerSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/sale/out/SaleOutForm.vue b/src/views/erp/sale/out/SaleOutForm.vue deleted file mode 100644 index 7d47713..0000000 --- a/src/views/erp/sale/out/SaleOutForm.vue +++ /dev/null @@ -1,343 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鍑哄簱鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍑哄簱鏃堕棿" prop="outTime"> - <el-date-picker - v-model="formData.outTime" - type="date" - value-format="x" - placeholder="閫夋嫨鍑哄簱鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input v-model="formData.orderNo" readonly> - <template #append> - <el-button @click="openSaleOrderOutEnableList"> - <Icon icon="ep:search" /> 閫夋嫨 - </el-button> - </template> - </el-input> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="formData.customerId" - clearable - filterable - disabled - placeholder="璇烽�夋嫨瀹㈡埛" - class="!w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閿�鍞汉鍛�" prop="saleUserId"> - <el-select - v-model="formData.saleUserId" - clearable - filterable - placeholder="璇烽�夋嫨閿�鍞汉鍛�" - class="!w-1/1" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="鍑哄簱浜у搧娓呭崟" name="item"> - <SaleOutItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鏀舵浼樻儬" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input - disabled - :model-value="formData.totalPrice - formData.otherPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏跺畠璐圭敤" prop="otherPrice"> - <el-input-number - v-model="formData.otherPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ュ叾瀹冭垂鐢�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="搴旀敹閲戦"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - - <!-- 鍙嚭搴撶殑璁㈠崟鍒楄〃 --> - <SaleOrderOutEnableList ref="saleOrderOutEnableListRef" @success="handleSaleOrderChange" /> -</template> -<script setup lang="ts"> -import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out' -import SaleOutItemForm from './components/SaleOutItemForm.vue' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import SaleOrderOutEnableList from '@/views/erp/sale/order/components/SaleOrderOutEnableList.vue' -import { SaleOrderVO } from '@/api/erp/sale/order' -import * as UserApi from '@/api/system/user' - -/** ERP 閿�鍞嚭搴撹〃鍗� */ -defineOptions({ name: 'SaleOutForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - outTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - orderNo: undefined, - items: [], - no: undefined // 鍑哄簱鍗曞彿锛屽悗绔繑鍥� -}) -const formRules = reactive({ - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - outTime: [{ required: true, message: '鍑哄簱鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - // 璁$畻 - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.discountPrice = discountPrice - formData.value.totalPrice = totalPrice - discountPrice + val.otherPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SaleOutApi.getSaleOut(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎵撳紑銆愬彲鍑哄簱鐨勮鍗曞垪琛ㄣ�戝脊绐� */ -const saleOrderOutEnableListRef = ref() // 鍙嚭搴撶殑璁㈠崟鍒楄〃 Ref -const openSaleOrderOutEnableList = () => { - saleOrderOutEnableListRef.value.open() -} - -const handleSaleOrderChange = (order: SaleOrderVO) => { - // 灏嗚鍗曡缃埌鍑哄簱鍗� - formData.value.orderId = order.id - formData.value.orderNo = order.no - formData.value.customerId = order.customerId - formData.value.accountId = order.accountId - formData.value.saleUserId = order.saleUserId - formData.value.discountPercent = order.discountPercent - formData.value.remark = order.remark - formData.value.fileUrl = order.fileUrl - // 灏嗚鍗曢」璁剧疆鍒板嚭搴撳崟椤� - order.items.forEach((item) => { - item.totalCount = item.count - item.count = item.totalCount - item.outCount - item.orderItemId = item.id - item.id = undefined - }) - formData.value.items = order.items.filter((item) => item.count > 0) -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as SaleOutVO - if (formType.value === 'create') { - await SaleOutApi.createSaleOut(data) - message.success(t('common.createSuccess')) - } else { - await SaleOutApi.updateSaleOut(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - outTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/sale/out/components/SaleOutItemForm.vue b/src/views/erp/sale/out/components/SaleOutItemForm.vue deleted file mode 100644 index 15cbef0..0000000 --- a/src/views/erp/sale/out/components/SaleOutItemForm.vue +++ /dev/null @@ -1,300 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="鍘熸暟閲�" - fixed="right" - min-width="80" - v-if="formData[0]?.totalCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.totalCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸插嚭搴�" - fixed="right" - min-width="80" - v-if="formData[0]?.outCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.outCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> - 鈥� - </el-button> - </template> - </el-table-column> - </el-table> - </el-form> -</template> -<script setup lang="ts"> -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - val.forEach((item) => { - if (item.warehouseId == null) { - item.warehouseId = defaultWarehouse.value?.id - } - if (item.stockCount === null && item.warehouseId != null) { - setStockCount(item) - } - }) - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) -}) -</script> diff --git a/src/views/erp/sale/out/components/SaleOutReceiptEnableList.vue b/src/views/erp/sale/out/components/SaleOutReceiptEnableList.vue deleted file mode 100644 index 0c4a21d..0000000 --- a/src/views/erp/sale/out/components/SaleOutReceiptEnableList.vue +++ /dev/null @@ -1,199 +0,0 @@ -<!-- 鍙敹娆剧殑閿�鍞嚭搴撳崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閿�鍞嚭搴擄紙浠呭睍绀哄彲鏀舵锛�" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍑哄簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍑哄簱鏃堕棿" prop="orderTime"> - <el-date-picker - v-model="queryParams.outTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍑哄簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="鍑哄簱鏃堕棿" - align="center" - prop="outTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="搴旀敹閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸叉敹閲戦" - align="center" - prop="receiptPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈敹閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.receiptPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.receiptPrice) }} - </el-tag> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out' - -defineOptions({ name: 'SaleOutReceiptEnableList' }) - -const list = ref<SaleOutVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - outTime: [], - receiptEnable: true, - customerId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleOutVO[]>([]) -const handleSelectionChange = (rows: SaleOutVO[]) => { - selectionList.value = rows -} - -/** 鎵撳紑寮圭獥 */ -const open = async (customerId: number) => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍙嚭搴撶殑璁㈠崟鍒楄〃 - queryParams.customerId = customerId - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: SaleOutVO[]): void -}>() -const submitForm = () => { - try { - emits('success', selectionList.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleOutApi.getSaleOutPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - selectionList.value = [] - getList() -} -</script> diff --git a/src/views/erp/sale/out/index.vue b/src/views/erp/sale/out/index.vue deleted file mode 100644 index bd143b9..0000000 --- a/src/views/erp/sale/out/index.vue +++ /dev/null @@ -1,438 +0,0 @@ -<template> - <doc-alert title="銆愰攢鍞�戦攢鍞鍗曘�佸嚭搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/sale/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍑哄簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍑哄簱鏃堕棿" prop="outTime"> - <el-date-picker - v-model="queryParams.outTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘鎴�" - class="!w-240px" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input - v-model="queryParams.orderNo" - placeholder="璇疯緭鍏ュ叧鑱旇鍗�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鏀舵鐘舵��" prop="receiptStatus"> - <el-select - v-model="queryParams.receiptStatus" - placeholder="璇烽�夋嫨鏈夋鐘舵��" - clearable - class="!w-240px" - > - <el-option label="鏈敹娆�" value="0" /> - <el-option label="閮ㄥ垎鏀舵" value="1" /> - <el-option label="鍏ㄩ儴鏀舵" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="瀹℃牳鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:sale-out:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:sale-out:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:sale-out:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍑哄簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column - label="鍑哄簱鏃堕棿" - align="center" - prop="outTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="搴旀敹閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸叉敹閲戦" - align="center" - prop="receiptPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈敹閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.receiptPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.receiptPrice) }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="瀹℃牳鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:sale-out:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:sale-out:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:sale-out:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:sale-out:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:sale-out:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SaleOutForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out' -import SaleOutForm from './SaleOutForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { - erpCountTableColumnFormatter, - erpPriceInputFormatter, - erpPriceTableColumnFormatter -} from '@/utils' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 閿�鍞嚭搴撳垪琛� */ -defineOptions({ name: 'ErpSaleOut' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<SaleOutVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - customerId: undefined, - productId: undefined, - warehouseId: undefined, - outTime: [], - orderNo: undefined, - receiptStatus: undefined, - accountId: undefined, - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleOutApi.getSaleOutPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SaleOutApi.deleteSaleOut(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ュ嚭搴撳悧锛焋) - // 鍙戣捣瀹℃壒 - await SaleOutApi.updateSaleOutStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await SaleOutApi.exportSaleOut(queryParams) - download.excel(data, '閿�鍞嚭搴�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleOutVO[]>([]) -const handleSelectionChange = (rows: SaleOutVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - customerList.value = await CustomerApi.getCustomerSimpleList() - userList.value = await UserApi.getSimpleUserList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/sale/return/SaleReturnForm.vue b/src/views/erp/sale/return/SaleReturnForm.vue deleted file mode 100644 index b10403b..0000000 --- a/src/views/erp/sale/return/SaleReturnForm.vue +++ /dev/null @@ -1,341 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閫�璐ф椂闂�" prop="returnTime"> - <el-date-picker - v-model="formData.returnTime" - type="date" - value-format="x" - placeholder="閫夋嫨閫�璐ф椂闂�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input v-model="formData.orderNo" readonly> - <template #append> - <el-button @click="openSaleOrderReturnEnableList"> - <Icon icon="ep:search" /> 閫夋嫨 - </el-button> - </template> - </el-input> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="formData.customerId" - clearable - filterable - disabled - placeholder="璇烽�夋嫨瀹㈡埛" - class="!w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閿�鍞汉鍛�" prop="saleUserId"> - <el-select - v-model="formData.saleUserId" - clearable - filterable - placeholder="璇烽�夋嫨閿�鍞汉鍛�" - class="!w-1/1" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="閫�璐т骇鍝佹竻鍗�" name="item"> - <SaleReturnItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="浼樻儬鐜囷紙%锛�" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ヤ紭鎯犵巼" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="閫�娆句紭鎯�" prop="discountPrice"> - <el-input - disabled - v-model="formData.discountPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="浼樻儬鍚庨噾棰�"> - <el-input - disabled - :model-value="formData.totalPrice - formData.otherPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏跺畠璐圭敤" prop="otherPrice"> - <el-input-number - v-model="formData.otherPrice" - controls-position="right" - :min="0" - :precision="2" - placeholder="璇疯緭鍏ュ叾瀹冭垂鐢�" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="formData.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-1/1" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="搴旈��閲戦" prop="totalPrice"> - <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - - <!-- 鍙��璐х殑璁㈠崟鍒楄〃 --> - <SaleOrderReturnEnableList ref="saleOrderReturnEnableListRef" @success="handleSaleOrderChange" /> -</template> -<script setup lang="ts"> -import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return' -import SaleReturnItemForm from './components/SaleReturnItemForm.vue' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' -import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils' -import SaleOrderReturnEnableList from '@/views/erp/sale/order/components/SaleOrderReturnEnableList.vue' -import { SaleOrderVO } from '@/api/erp/sale/order' -import * as UserApi from '@/api/system/user' - -/** ERP 閿�鍞��璐ц〃鍗� */ -defineOptions({ name: 'SaleReturnForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - returnTime: undefined, - remark: undefined, - fileUrl: '', - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - orderNo: undefined, - items: [], - no: undefined // 閫�璐у崟鍙凤紝鍚庣杩斿洖 -}) -const formRules = reactive({ - customerId: [{ required: true, message: '瀹㈡埛涓嶈兘涓虹┖', trigger: 'blur' }], - returnTime: [{ required: true, message: '閫�璐ф椂闂翠笉鑳戒负绌�', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 -const userList = ref<UserApi.UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 璁$畻 discountPrice銆乼otalPrice 浠锋牸 */ -watch( - () => formData.value, - (val) => { - if (!val) { - return - } - // 璁$畻 - const totalPrice = val.items.reduce((prev, curr) => prev + curr.totalPrice, 0) - const discountPrice = - val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0 - formData.value.totalPrice = totalPrice - discountPrice + val.otherPrice - }, - { deep: true } -) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SaleReturnApi.getSaleReturn(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() - // 鍔犺浇鐢ㄦ埛鍒楄〃 - userList.value = await UserApi.getSimpleUserList() - // 鍔犺浇璐︽埛鍒楄〃 - accountList.value = await AccountApi.getAccountSimpleList() - const defaultAccount = accountList.value.find((item) => item.defaultStatus) - if (defaultAccount) { - formData.value.accountId = defaultAccount.id - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎵撳紑銆愬彲閫�璐х殑璁㈠崟鍒楄〃銆戝脊绐� */ -const saleOrderReturnEnableListRef = ref() // 鍙��璐х殑璁㈠崟鍒楄〃 Ref -const openSaleOrderReturnEnableList = () => { - saleOrderReturnEnableListRef.value.open() -} - -const handleSaleOrderChange = (order: SaleOrderVO) => { - // 灏嗚鍗曡缃埌閫�璐у崟 - formData.value.orderId = order.id - formData.value.orderNo = order.no - formData.value.customerId = order.customerId - formData.value.accountId = order.accountId - formData.value.saleUserId = order.saleUserId - formData.value.discountPercent = order.discountPercent - formData.value.remark = order.remark - formData.value.fileUrl = order.fileUrl - // 灏嗚鍗曢」璁剧疆鍒伴��璐у崟椤� - order.items.forEach((item) => { - item.count = item.outCount - item.returnCount - item.orderItemId = item.id - item.id = undefined - }) - formData.value.items = order.items.filter((item) => item.count > 0) -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as SaleReturnVO - if (formType.value === 'create') { - await SaleReturnApi.createSaleReturn(data) - message.success(t('common.createSuccess')) - } else { - await SaleReturnApi.updateSaleReturn(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - accountId: undefined, - saleUserId: undefined, - returnTime: undefined, - remark: undefined, - fileUrl: undefined, - discountPercent: 0, - discountPrice: 0, - totalPrice: 0, - otherPrice: 0, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/sale/return/components/SaleReturnItemForm.vue b/src/views/erp/sale/return/components/SaleReturnItemForm.vue deleted file mode 100644 index adb9fd4..0000000 --- a/src/views/erp/sale/return/components/SaleReturnItemForm.vue +++ /dev/null @@ -1,300 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸插嚭搴�" - fixed="right" - min-width="80" - v-if="formData[0]?.outCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.outCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column - label="宸查��璐�" - fixed="right" - min-width="80" - v-if="formData[0]?.returnCount != null" - > - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.returnCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="閲戦" prop="totalProductPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!"> - <el-input - disabled - v-model="row.totalProductPrice" - :formatter="erpPriceInputFormatter" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庣巼锛�%锛�" fixed="right" min-width="115"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!"> - <el-input-number - v-model="row.taxPercent" - controls-position="right" - :min="0" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨" prop="taxPrice" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> - <el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="绋庨鍚堣" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> - 鈥� - </el-button> - </template> - </el-table-column> - </el-table> - </el-form> -</template> -<script setup lang="ts"> -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - val.forEach((item) => { - if (item.warehouseId == null) { - item.warehouseId = defaultWarehouse.value?.id - } - if (item.stockCount === null && item.warehouseId != null) { - setStockCount(item) - } - }) - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalProductPrice = erpPriceMultiply(item.productPrice, item.count) - item.taxPrice = erpPriceMultiply(item.totalProductPrice, item.taxPercent / 100.0) - if (item.totalProductPrice != null) { - item.totalPrice = item.totalProductPrice + (item.taxPrice || 0) - } else { - item.totalPrice = undefined - } - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index: number) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalProductPrice: undefined, - taxPercent: undefined, - taxPrice: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index: number) => { - formData.value.splice(index, 1) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row: any) => { - if (!row.productId) { - return - } - const count = await StockApi.getStockCount(row.productId) - row.stockCount = count || 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) -}) -</script> diff --git a/src/views/erp/sale/return/components/SaleReturnRefundEnableList.vue b/src/views/erp/sale/return/components/SaleReturnRefundEnableList.vue deleted file mode 100644 index dc875e6..0000000 --- a/src/views/erp/sale/return/components/SaleReturnRefundEnableList.vue +++ /dev/null @@ -1,199 +0,0 @@ -<!-- 鍙��娆剧殑閿�鍞��璐у崟鍒楄〃 --> -<template> - <Dialog - title="閫夋嫨閿�鍞��璐э紙浠呭睍绀哄彲閫�娆撅級" - v-model="dialogVisible" - :appendToBody="true" - :scroll="true" - width="1080" - > - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ラ��璐у崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-160px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-160px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф椂闂�" prop="orderTime"> - <el-date-picker - v-model="queryParams.returnTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-160px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="閫�璐у崟鍙�" align="center" prop="no" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="閫�璐ф椂闂�" - align="center" - prop="returnTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="搴旈��閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸查��閲戦" - align="center" - prop="refundPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈��閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }} - </el-tag> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import { dateFormatter2 } from '@/utils/formatTime' -import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return' - -defineOptions({ name: 'SaleReturnPaymentEnableList' }) - -const list = ref<SaleReturnVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - returnTime: [], - refundEnable: true, - customerId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleReturnVO[]>([]) -const handleSelectionChange = (rows: SaleReturnVO[]) => { - selectionList.value = rows -} - -/** 鎵撳紑寮圭獥 */ -const open = async (customerId: number) => { - dialogVisible.value = true - await nextTick() // 绛夊緟锛岄伩鍏� queryFormRef 涓虹┖ - // 鍔犺浇鍒楄〃 - queryParams.customerId = customerId - await resetQuery() - // 鍔犺浇浜у搧鍒楄〃 - productList.value = await ProductApi.getProductSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦閫夋嫨 */ -const emits = defineEmits<{ - (e: 'success', value: SaleReturnVO[]): void -}>() -const submitForm = () => { - try { - emits('success', selectionList.value) - } finally { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - } -} - -/** 鍔犺浇鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleReturnApi.getSaleReturnPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - selectionList.value = [] - getList() -} -</script> diff --git a/src/views/erp/sale/return/index.vue b/src/views/erp/sale/return/index.vue deleted file mode 100644 index c88f584..0000000 --- a/src/views/erp/sale/return/index.vue +++ /dev/null @@ -1,443 +0,0 @@ -<template> - <doc-alert title="銆愰攢鍞�戦攢鍞鍗曘�佸嚭搴撱�侀��璐�" url="https://doc.iocoder.cn/erp/sale/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="閫�璐у崟鍙�" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ラ��璐у崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐ф椂闂�" prop="outTime"> - <el-date-picker - v-model="queryParams.outTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘鎴�" - class="!w-240px" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏宠仈璁㈠崟" prop="orderNo"> - <el-input - v-model="queryParams.orderNo" - placeholder="璇疯緭鍏ュ叧鑱旇鍗�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="缁撶畻璐︽埛" prop="accountId"> - <el-select - v-model="queryParams.accountId" - clearable - filterable - placeholder="璇烽�夋嫨缁撶畻璐︽埛" - class="!w-240px" - > - <el-option - v-for="item in accountList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�娆剧姸鎬�" prop="refundStatus"> - <el-select - v-model="queryParams.refundStatus" - placeholder="璇烽�夋嫨閫�娆剧姸鎬�" - clearable - class="!w-240px" - > - <el-option label="鏈��娆�" value="0" /> - <el-option label="閮ㄥ垎閫�娆�" value="1" /> - <el-option label="鍏ㄩ儴閫�娆�" value="2" /> - </el-select> - </el-form-item> - <el-form-item label="瀹℃牳鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨瀹℃牳鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:sale-return:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:sale-return:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:sale-return:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="閫�璐у崟鍙�" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column - label="閫�璐ф椂闂�" - align="center" - prop="returnTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鎬绘暟閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="搴旈��閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="宸查��閲戦" - align="center" - prop="refundPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鏈��閲戦" align="center"> - <template #default="scope"> - <span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span> - <el-tag type="danger" v-else> - {{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="瀹℃牳鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:sale-return:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:sale-return:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:sale-return:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:sale-return:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:sale-return:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SaleReturnForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return' -import SaleReturnForm from './SaleReturnForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { - erpCountTableColumnFormatter, - erpPriceInputFormatter, - erpPriceTableColumnFormatter -} from '@/utils' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { AccountApi, AccountVO } from '@/api/erp/finance/account' - -/** ERP 閿�鍞��璐у垪琛� */ -defineOptions({ name: 'ErpSaleReturn' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<SaleReturnVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - customerId: undefined, - productId: undefined, - warehouseId: undefined, - returnTime: [], - orderNo: undefined, - accountId: undefined, - status: undefined, - remark: undefined, - creator: undefined, - refundStatus: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const accountList = ref<AccountVO[]>([]) // 璐︽埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SaleReturnApi.getSaleReturnPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SaleReturnApi.deleteSaleReturn(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ラ��璐у悧锛焋) - // 鍙戣捣瀹℃壒 - await SaleReturnApi.updateSaleReturnStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await SaleReturnApi.exportSaleReturn(queryParams) - download.excel(data, '閿�鍞��璐�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<SaleReturnVO[]>([]) -const handleSelectionChange = (rows: SaleReturnVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - customerList.value = await CustomerApi.getCustomerSimpleList() - userList.value = await UserApi.getSimpleUserList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - accountList.value = await AccountApi.getAccountSimpleList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/stock/check/StockCheckForm.vue b/src/views/erp/stock/check/StockCheckForm.vue deleted file mode 100644 index 9e7f673..0000000 --- a/src/views/erp/stock/check/StockCheckForm.vue +++ /dev/null @@ -1,148 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鐩樼偣鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鐩樼偣鏃堕棿" prop="checkTime"> - <el-date-picker - v-model="formData.checkTime" - type="date" - value-format="x" - placeholder="閫夋嫨鐩樼偣鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="鐩樼偣浜у搧娓呭崟" name="item"> - <StockCheckItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { StockCheckApi, StockCheckVO } from '@/api/erp/stock/check' -import StockCheckItemForm from './components/StockCheckItemForm.vue' - -/** ERP 鍏跺畠鐩樼偣鍗曡〃鍗� */ -defineOptions({ name: 'StockCheckForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - checkTime: undefined, - remark: undefined, - fileUrl: '', - items: [] -}) -const formRules = reactive({ - checkTime: [{ required: true, message: '鐩樼偣鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await StockCheckApi.getStockCheck(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as StockCheckVO - if (formType.value === 'create') { - await StockCheckApi.createStockCheck(data) - message.success(t('common.createSuccess')) - } else { - await StockCheckApi.updateStockCheck(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - checkTime: undefined, - remark: undefined, - fileUrl: undefined, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/stock/check/components/StockCheckItemForm.vue b/src/views/erp/stock/check/components/StockCheckItemForm.vue deleted file mode 100644 index 6036311..0000000 --- a/src/views/erp/stock/check/components/StockCheckItemForm.vue +++ /dev/null @@ -1,289 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶅瓧" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱鍚嶅瓧" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="璐﹂潰搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="瀹為檯搴撳瓨" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.actualCount`" - :rules="formRules.actualCount" - class="mb-0px!" - > - <el-input-number - v-model="row.actualCount" - controls-position="right" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鐩堜簭鏁伴噺" prop="count" fixed="right" min-width="110"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input - disabled - v-model="row.count" - :formatter="erpCountInputFormatter" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞鐩樼偣浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - inId: [{ required: true, message: '鐩樼偣缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - warehouseId: [{ required: true, message: '浠撳簱鍚嶅瓧涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃洏鐐归」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - if (item.stockCount != null && item.actualCount != null) { - item.count = item.actualCount - item.stockCount - } else { - item.count = undefined - } - item.totalPrice = erpPriceMultiply(item.productPrice, item.count) - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - warehouseId: defaultWarehouse.value?.id, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - actualCount: undefined, - count: undefined, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浠撳簱鍙樻洿 */ -const onChangeWarehouse = (warehouseId, row) => { - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.minPrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row) => { - if (!row.productId || !row.warehouseId) { - return - } - const stock = await StockApi.getStock2(row.productId, row.warehouseId) - row.stockCount = stock ? stock.count : 0 - row.actualCount = row.stockCount -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/stock/check/index.vue b/src/views/erp/stock/check/index.vue deleted file mode 100644 index f661ab7..0000000 --- a/src/views/erp/stock/check/index.vue +++ /dev/null @@ -1,359 +0,0 @@ -<template> - <doc-alert - title="銆愬簱瀛樸�戝簱瀛樿皟鎷ㄣ�佸簱瀛樼洏鐐�" - url="https://doc.iocoder.cn/erp/stock-move-check/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐩樼偣鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ョ洏鐐瑰崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐩樼偣鏃堕棿" prop="checkTime"> - <el-date-picker - v-model="queryParams.checkTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock-check:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock-check:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:stock-check:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鐩樼偣鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="鐩樼偣鏃堕棿" - align="center" - prop="checkTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鏁伴噺" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:stock-check:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:stock-check:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:stock-check:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:stock-check:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:stock-check:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <StockCheckForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { StockCheckApi, StockCheckVO } from '@/api/erp/stock/check' -import StockCheckForm from './StockCheckForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' - -/** ERP 鍏跺畠鐩樼偣鍗曞垪琛� */ -defineOptions({ name: 'ErpStockCheck' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockCheckVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - warehouseId: undefined, - checkTime: [], - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockCheckApi.getStockCheckPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockCheckApi.deleteStockCheck(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ョ洏鐐瑰崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await StockCheckApi.updateStockCheckStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockCheckApi.exportStockCheck(queryParams) - download.excel(data, '鍏跺畠鐩樼偣鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<StockCheckVO[]>([]) -const handleSelectionChange = (rows: StockCheckVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/stock/in/StockInForm.vue b/src/views/erp/stock/in/StockInForm.vue deleted file mode 100644 index f36bbb6..0000000 --- a/src/views/erp/stock/in/StockInForm.vue +++ /dev/null @@ -1,170 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鍏ュ簱鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍏ュ簱鏃堕棿" prop="inTime"> - <el-date-picker - v-model="formData.inTime" - type="date" - value-format="x" - placeholder="閫夋嫨鍏ュ簱鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="formData.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-1/1" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="鍏ュ簱浜у搧娓呭崟" name="item"> - <StockInItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { StockInApi, StockInVO } from '@/api/erp/stock/in' -import StockInItemForm from './components/StockInItemForm.vue' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' - -/** ERP 鍏跺畠鍏ュ簱鍗� 琛ㄥ崟 */ -defineOptions({ name: 'StockInForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - supplierId: undefined, - inTime: undefined, - remark: undefined, - fileUrl: '', - items: [] -}) -const formRules = reactive({ - inTime: [{ required: true, message: '鍏ュ簱鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await StockInApi.getStockIn(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇渚涘簲鍟嗗垪琛� - supplierList.value = await SupplierApi.getSupplierSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as StockInVO - if (formType.value === 'create') { - await StockInApi.createStockIn(data) - message.success(t('common.createSuccess')) - } else { - await StockInApi.updateStockIn(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - supplierId: undefined, - inTime: undefined, - remark: undefined, - fileUrl: undefined, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/stock/in/components/StockInItemForm.vue b/src/views/erp/stock/in/components/StockInItemForm.vue deleted file mode 100644 index 53a2fd2..0000000 --- a/src/views/erp/stock/in/components/StockInItemForm.vue +++ /dev/null @@ -1,267 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞鍏ュ簱浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - inId: [{ required: true, message: '鍏ュ簱缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃叆搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalPrice = erpPriceMultiply(item.productPrice, item.count) - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - warehouseId: defaultWarehouse.value?.id, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浠撳簱鍙樻洿 */ -const onChangeWarehouse = (warehouseId, row) => { - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.minPrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row) => { - if (!row.productId || !row.warehouseId) { - return - } - const stock = await StockApi.getStock2(row.productId, row.warehouseId) - row.stockCount = stock ? stock.count : 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/stock/in/index.vue b/src/views/erp/stock/in/index.vue deleted file mode 100644 index 5a8f6cf..0000000 --- a/src/views/erp/stock/in/index.vue +++ /dev/null @@ -1,376 +0,0 @@ -<template> - <doc-alert title="銆愬簱瀛樸�戝叾瀹冨叆搴撱�佸叾瀹冨嚭搴�" url="https://doc.iocoder.cn/erp/stock-in-out/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍏ュ簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏ュ簱鏃堕棿" prop="inTime"> - <el-date-picker - v-model="queryParams.inTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item label="渚涘簲鍟�" prop="supplierId"> - <el-select - v-model="queryParams.supplierId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘簲鍟�" - class="!w-240px" - > - <el-option - v-for="item in supplierList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock-in:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock-in:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:stock-in:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍏ュ簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="渚涘簲鍟�" align="center" prop="supplierName" /> - <el-table-column - label="鍏ュ簱鏃堕棿" - align="center" - prop="inTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鏁伴噺" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:stock-in:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:stock-in:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:stock-in:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:stock-in:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:stock-in:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <StockInForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { StockInApi, StockInVO } from '@/api/erp/stock/in' -import StockInForm from './StockInForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' - -/** ERP 鍏跺畠鍏ュ簱鍗曞垪琛� */ -defineOptions({ name: 'ErpStockIn' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockInVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - supplierId: undefined, - inTime: [], - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const supplierList = ref<SupplierVO[]>([]) // 渚涘簲鍟嗗垪琛� -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockInApi.getStockInPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockInApi.deleteStockIn(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ュ叆搴撳崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await StockInApi.updateStockInStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockInApi.exportStockIn(queryParams) - download.excel(data, '鍏跺畠鍏ュ簱鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<StockInVO[]>([]) -const handleSelectionChange = (rows: StockInVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佷緵搴斿晢 - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - supplierList.value = await SupplierApi.getSupplierSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/stock/move/StockMoveForm.vue b/src/views/erp/stock/move/StockMoveForm.vue deleted file mode 100644 index df942c6..0000000 --- a/src/views/erp/stock/move/StockMoveForm.vue +++ /dev/null @@ -1,148 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="璋冨害鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="璋冨害鏃堕棿" prop="moveTime"> - <el-date-picker - v-model="formData.moveTime" - type="date" - value-format="x" - placeholder="閫夋嫨璋冨害鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="璋冨害浜у搧娓呭崟" name="item"> - <StockMoveItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { StockMoveApi, StockMoveVO } from '@/api/erp/stock/move' -import StockMoveItemForm from './components/StockMoveItemForm.vue' - -/** ERP 搴撳瓨璋冨害鍗曡〃鍗� */ -defineOptions({ name: 'StockMoveForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - moveTime: undefined, - remark: undefined, - fileUrl: '', - items: [] -}) -const formRules = reactive({ - moveTime: [{ required: true, message: '璋冨害鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await StockMoveApi.getStockMove(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as StockMoveVO - if (formType.value === 'create') { - await StockMoveApi.createStockMove(data) - message.success(t('common.createSuccess')) - } else { - await StockMoveApi.updateStockMove(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - moveTime: undefined, - remark: undefined, - fileUrl: undefined, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/stock/move/components/StockMoveItemForm.vue b/src/views/erp/stock/move/components/StockMoveItemForm.vue deleted file mode 100644 index 8971956..0000000 --- a/src/views/erp/stock/move/components/StockMoveItemForm.vue +++ /dev/null @@ -1,292 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="璋冨嚭浠撳簱" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.fromWarehouseId`" - :rules="formRules.fromWarehouseId" - class="mb-0px!" - > - <el-select - v-model="row.fromWarehouseId" - clearable - filterable - placeholder="璇烽�夋嫨璋冨嚭浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="璋冨叆浠撳簱" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.toWarehouseId`" - :rules="formRules.toWarehouseId" - class="mb-0px!" - > - <el-select - v-model="row.toWarehouseId" - clearable - filterable - placeholder="璇烽�夋嫨璋冨叆浠撳簱" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞璋冨害浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - inId: [{ required: true, message: '璋冨害缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - fromWarehouseId: [{ required: true, message: '璋冨嚭浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - toWarehouseId: [{ required: true, message: '璋冨叆浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃皟搴﹂」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalPrice = erpPriceMultiply(item.productPrice, item.count) - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - fromWarehouseId: defaultWarehouse.value?.id, - toWarehouseId: undefined, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浠撳簱鍙樻洿 */ -const onChangeWarehouse = (warehouseId, row) => { - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.minPrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row) => { - if (!row.productId || !row.fromWarehouseId) { - return - } - const stock = await StockApi.getStock2(row.productId, row.fromWarehouseId) - row.stockCount = stock ? stock.count : 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/stock/move/index.vue b/src/views/erp/stock/move/index.vue deleted file mode 100644 index 76ea653..0000000 --- a/src/views/erp/stock/move/index.vue +++ /dev/null @@ -1,359 +0,0 @@ -<template> - <doc-alert - title="銆愬簱瀛樸�戝簱瀛樿皟鎷ㄣ�佸簱瀛樼洏鐐�" - url="https://doc.iocoder.cn/erp/stock-move-check/" - /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="璋冨害鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ皟搴﹀崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="璋冨害鏃堕棿" prop="moveTime"> - <el-date-picker - v-model="queryParams.moveTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浠撳簱" prop="fromWarehouseId"> - <el-select - v-model="queryParams.fromWarehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock-move:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock-move:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:stock-move:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="璋冨害鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column - label="璋冨害鏃堕棿" - align="center" - prop="moveTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鏁伴噺" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:stock-move:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:stock-move:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:stock-move:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:stock-move:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:stock-move:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <StockMoveForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { StockMoveApi, StockMoveVO } from '@/api/erp/stock/move' -import StockMoveForm from './StockMoveForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' - -/** ERP 搴撳瓨璋冨害鍗曞垪琛� */ -defineOptions({ name: 'ErpStockMove' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockMoveVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - fromWarehouseId: undefined, - moveTime: [], - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockMoveApi.getStockMovePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockMoveApi.deleteStockMove(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ヨ皟搴﹀崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await StockMoveApi.updateStockMoveStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockMoveApi.exportStockMove(queryParams) - download.excel(data, '搴撳瓨璋冨害鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<StockMoveVO[]>([]) -const handleSelectionChange = (rows: StockMoveVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/stock/out/StockOutForm.vue b/src/views/erp/stock/out/StockOutForm.vue deleted file mode 100644 index 8ae8d63..0000000 --- a/src/views/erp/stock/out/StockOutForm.vue +++ /dev/null @@ -1,170 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - :disabled="disabled" - > - <el-row :gutter="20"> - <el-col :span="8"> - <el-form-item label="鍑哄簱鍗曞彿" prop="no"> - <el-input disabled v-model="formData.no" placeholder="淇濆瓨鏃惰嚜鍔ㄧ敓鎴�" /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鍑哄簱鏃堕棿" prop="outTime"> - <el-date-picker - v-model="formData.outTime" - type="date" - value-format="x" - placeholder="閫夋嫨鍑哄簱鏃堕棿" - class="!w-1/1" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="formData.customerId" - clearable - filterable - placeholder="璇烽�夋嫨瀹㈡埛" - class="!w-1/1" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="16"> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - type="textarea" - v-model="formData.remark" - :rows="1" - placeholder="璇疯緭鍏ュ娉�" - /> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="闄勪欢" prop="fileUrl"> - <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <!-- 瀛愯〃鐨勮〃鍗� --> - <ContentWrap> - <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> - <el-tab-pane label="鍑哄簱浜у搧娓呭崟" name="item"> - <StockOutItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> - 纭� 瀹� - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { StockOutApi, StockOutVO } from '@/api/erp/stock/out' -import StockOutItemForm from './components/StockOutItemForm.vue' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' - -/** ERP 鍏跺畠鍑哄簱鍗曡〃鍗� */ -defineOptions({ name: 'StockOutForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼锛沝etail - 璇︽儏 -const formData = ref({ - id: undefined, - customerId: undefined, - outTime: undefined, - remark: undefined, - fileUrl: '', - items: [] -}) -const formRules = reactive({ - outTime: [{ required: true, message: '鍑哄簱鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const disabled = computed(() => formType.value === 'detail') -const formRef = ref() // 琛ㄥ崟 Ref -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 - -/** 瀛愯〃鐨勮〃鍗� */ -const subTabsName = ref('item') -const itemFormRef = ref() - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await StockOutApi.getStockOut(id) - } finally { - formLoading.value = false - } - } - // 鍔犺浇瀹㈡埛鍒楄〃 - customerList.value = await CustomerApi.getCustomerSimpleList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - await itemFormRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as StockOutVO - if (formType.value === 'create') { - await StockOutApi.createStockOut(data) - message.success(t('common.createSuccess')) - } else { - await StockOutApi.updateStockOut(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - customerId: undefined, - outTime: undefined, - remark: undefined, - fileUrl: undefined, - items: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/stock/out/components/StockOutItemForm.vue b/src/views/erp/stock/out/components/StockOutItemForm.vue deleted file mode 100644 index b09a569..0000000 --- a/src/views/erp/stock/out/components/StockOutItemForm.vue +++ /dev/null @@ -1,267 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - :disabled="disabled" - > - <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> - <el-table-column label="搴忓彿" type="index" align="center" width="60" /> - <el-table-column label="浠撳簱鍚嶇О" min-width="125"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.warehouseId`" - :rules="formRules.warehouseId" - class="mb-0px!" - > - <el-select - v-model="row.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - @change="onChangeWarehouse($event, row)" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍚嶇О" min-width="180"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> - <el-select - v-model="row.productId" - clearable - filterable - @change="onChangeProduct($event, row)" - placeholder="璇烽�夋嫨浜у搧" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" min-width="100"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏉$爜" min-width="150"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productBarCode" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍗曚綅" min-width="80"> - <template #default="{ row }"> - <el-form-item class="mb-0px!"> - <el-input disabled v-model="row.productUnitName" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" fixed="right" min-width="140"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> - <el-input-number - v-model="row.count" - controls-position="right" - :min="0.001" - :precision="3" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="浜у搧鍗曚环" fixed="right" min-width="120"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> - <el-input-number - v-model="row.productPrice" - controls-position="right" - :min="0.01" - :precision="2" - class="!w-100%" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="鍚堣閲戦" prop="totalPrice" fixed="right" min-width="100"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!"> - <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.remark`" class="mb-0px!"> - <el-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>鈥�</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3" v-if="!disabled"> - <el-button @click="handleAdd" round>+ 娣诲姞鍑哄簱浜у搧</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { StockApi } from '@/api/erp/stock/stock' -import { - erpCountInputFormatter, - erpPriceInputFormatter, - erpPriceMultiply, - getSumValue -} from '@/utils' - -const props = defineProps<{ - items: undefined - disabled: false -}>() -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref([]) -const formRules = reactive({ - inId: [{ required: true, message: '鍑哄簱缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }], - warehouseId: [{ required: true, message: '浠撳簱涓嶈兘涓虹┖', trigger: 'blur' }], - productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'blur' }], - count: [{ required: true, message: '浜у搧鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const defaultWarehouse = ref<WarehouseVO>(undefined) // 榛樿浠撳簱 - -/** 鍒濆鍖栬缃嚭搴撻」 */ -watch( - () => props.items, - async (val) => { - formData.value = val - }, - { immediate: true } -) - -/** 鐩戝惉鍚堝悓浜у搧鍙樺寲锛岃绠楀悎鍚屼骇鍝佹�讳环 */ -watch( - () => formData.value, - (val) => { - if (!val || val.length === 0) { - return - } - // 寰幆澶勭悊 - val.forEach((item) => { - item.totalPrice = erpPriceMultiply(item.productPrice, item.count) - }) - }, - { deep: true } -) - -/** 鍚堣 */ -const getSummaries = (param: SummaryMethodProps) => { - const { columns, data } = param - const sums: string[] = [] - columns.forEach((column, index) => { - if (index === 0) { - sums[index] = '鍚堣' - return - } - if (['count', 'totalPrice'].includes(column.property)) { - const sum = getSumValue(data.map((item) => Number(item[column.property]))) - sums[index] = - column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum) - } else { - sums[index] = '' - } - }) - - return sums -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const handleAdd = () => { - const row = { - id: undefined, - warehouseId: defaultWarehouse.value?.id, - productId: undefined, - productUnitName: undefined, // 浜у搧鍗曚綅 - productBarCode: undefined, // 浜у搧鏉$爜 - productPrice: undefined, - stockCount: undefined, - count: 1, - totalPrice: undefined, - remark: undefined - } - formData.value.push(row) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 澶勭悊浠撳簱鍙樻洿 */ -const onChangeWarehouse = (warehouseId, row) => { - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 澶勭悊浜у搧鍙樻洿 */ -const onChangeProduct = (productId, row) => { - const product = productList.value.find((item) => item.id === productId) - if (product) { - row.productUnitName = product.unitName - row.productBarCode = product.barCode - row.productPrice = product.minPrice - } - // 鍔犺浇搴撳瓨 - setStockCount(row) -} - -/** 鍔犺浇搴撳瓨 */ -const setStockCount = async (row) => { - if (!row.productId || !row.warehouseId) { - return - } - const stock = await StockApi.getStock2(row.productId, row.warehouseId) - row.stockCount = stock ? stock.count : 0 -} - -/** 琛ㄥ崟鏍¢獙 */ -const validate = () => { - return formRef.value.validate() -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -onMounted(async () => { - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) - // 榛樿娣诲姞涓�涓� - if (formData.value.length === 0) { - handleAdd() - } -}) -</script> diff --git a/src/views/erp/stock/out/index.vue b/src/views/erp/stock/out/index.vue deleted file mode 100644 index 555b985..0000000 --- a/src/views/erp/stock/out/index.vue +++ /dev/null @@ -1,378 +0,0 @@ -<template> - <doc-alert title="銆愬簱瀛樸�戝叾瀹冨叆搴撱�佸叾瀹冨嚭搴�" url="https://doc.iocoder.cn/erp/stock-in-out/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍑哄簱鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍑哄簱鏃堕棿" prop="outTime"> - <el-date-picker - v-model="queryParams.outTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="瀹㈡埛" prop="customerId"> - <el-select - v-model="queryParams.customerId" - clearable - filterable - placeholder="璇烽�夋嫨渚涘鎴�" - class="!w-240px" - > - <el-option - v-for="item in customerList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓浜�" prop="creator"> - <el-select - v-model="queryParams.creator" - clearable - filterable - placeholder="璇烽�夋嫨鍒涘缓浜�" - class="!w-240px" - > - <el-option - v-for="item in userList" - :key="item.id" - :label="item.nickname" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input - v-model="queryParams.remark" - placeholder="璇疯緭鍏ュ娉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock-out:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock-out:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - <el-button - type="danger" - plain - @click="handleDelete(selectionList.map((item) => item.id))" - v-hasPermi="['erp:stock-out:delete']" - :disabled="selectionList.length === 0" - > - <Icon icon="ep:delete" class="mr-5px" /> 鍒犻櫎 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - @selection-change="handleSelectionChange" - > - <el-table-column width="30" label="閫夋嫨" type="selection" /> - <el-table-column min-width="180" label="鍑哄簱鍗曞彿" align="center" prop="no" /> - <el-table-column label="浜у搧淇℃伅" align="center" prop="productNames" min-width="200" /> - <el-table-column label="瀹㈡埛" align="center" prop="customerName" /> - <el-table-column - label="鍑哄簱鏃堕棿" - align="center" - prop="outTime" - :formatter="dateFormatter2" - width="120px" - /> - <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" /> - <el-table-column - label="鏁伴噺" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="閲戦" - align="center" - prop="totalPrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="鐘舵��" align="center" fixed="right" width="90" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right" width="220"> - <template #default="scope"> - <el-button - link - @click="openForm('detail', scope.row.id)" - v-hasPermi="['erp:stock-out:query']" - > - 璇︽儏 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:stock-out:update']" - :disabled="scope.row.status === 20" - > - 缂栬緫 - </el-button> - <el-button - link - type="primary" - @click="handleUpdateStatus(scope.row.id, 20)" - v-hasPermi="['erp:stock-out:update-status']" - v-if="scope.row.status === 10" - > - 瀹℃壒 - </el-button> - <el-button - link - type="danger" - @click="handleUpdateStatus(scope.row.id, 10)" - v-hasPermi="['erp:stock-out:update-status']" - v-else - > - 鍙嶅鎵� - </el-button> - <el-button - link - type="danger" - @click="handleDelete([scope.row.id])" - v-hasPermi="['erp:stock-out:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <StockOutForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter2 } from '@/utils/formatTime' -import download from '@/utils/download' -import { StockOutApi, StockOutVO } from '@/api/erp/stock/out' -import StockOutForm from './StockOutForm.vue' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { SupplierApi, SupplierVO } from '@/api/erp/purchase/supplier' -import { UserVO } from '@/api/system/user' -import * as UserApi from '@/api/system/user' -import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' -import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' - -/** ERP 鍏跺畠鍑哄簱鍗曞垪琛� */ -defineOptions({ name: 'ErpStockOut' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockOutVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: undefined, - productId: undefined, - customerId: undefined, - warehouseId: undefined, - outTime: [], - status: undefined, - remark: undefined, - creator: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 -const customerList = ref<CustomerVO[]>([]) // 瀹㈡埛鍒楄〃 -const userList = ref<UserVO[]>([]) // 鐢ㄦ埛鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockOutApi.getStockOutPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (ids: number[]) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockOutApi.deleteStockOut(ids) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id)) - } catch {} -} - -/** 瀹℃壒/鍙嶅鎵规搷浣� */ -const handleUpdateStatus = async (id: number, status: number) => { - try { - // 瀹℃壒鐨勪簩娆$‘璁� - await message.confirm(`纭畾${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}璇ュ嚭搴撳崟鍚楋紵`) - // 鍙戣捣瀹℃壒 - await StockOutApi.updateStockOutStatus(id, status) - message.success(`${status === 20 ? '瀹℃壒' : '鍙嶅鎵�'}鎴愬姛`) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockOutApi.exportStockOut(queryParams) - download.excel(data, '鍏跺畠鍑哄簱鍗�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 閫変腑鎿嶄綔 */ -const selectionList = ref<StockOutVO[]>([]) -const handleSelectionChange = (rows: StockOutVO[]) => { - selectionList.value = rows -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛ㄣ�佸鎴� - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() - customerList.value = await CustomerApi.getCustomerSimpleList() - userList.value = await UserApi.getSimpleUserList() -}) -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氬垪琛ㄧ晫闈紝鏀寔瀵煎叆 -// TODO 鑺嬭壙锛氬彲浼樺寲鍔熻兘锛氳鎯呯晫闈紝鏀寔鎵撳嵃 -</script> diff --git a/src/views/erp/stock/record/index.vue b/src/views/erp/stock/record/index.vue deleted file mode 100644 index 6946a19..0000000 --- a/src/views/erp/stock/record/index.vue +++ /dev/null @@ -1,250 +0,0 @@ -<!-- ERP 浜у搧搴撳瓨鏄庣粏鍒楄〃 --> -<template> - <doc-alert title="銆愬簱瀛樸�戜骇鍝佸簱瀛樸�佸簱瀛樻槑缁�" url="https://doc.iocoder.cn/erp/stock/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="绫诲瀷" prop="bizType"> - <el-select - v-model="queryParams.bizType" - placeholder="璇烽�夋嫨绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.ERP_STOCK_RECORD_BIZ_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="涓氬姟鍗曞彿" prop="bizNo"> - <el-input - v-model="queryParams.bizNo" - placeholder="璇疯緭鍏ヤ笟鍔″崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-220px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock-record:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock-record:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="浜у搧鍚嶇О" align="center" prop="productName" /> - <el-table-column label="浜у搧鍒嗙被" align="center" prop="categoryName" /> - <el-table-column label="浜у搧鍗曚綅" align="center" prop="unitName" /> - <el-table-column label="浠撳簱缂栧彿" align="center" prop="warehouseName" /> - <el-table-column label="绫诲瀷" align="center" prop="bizType" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.ERP_STOCK_RECORD_BIZ_TYPE" :value="scope.row.bizType" /> - </template> - </el-table-column> - <el-table-column label="鍑哄叆搴撳崟鍙�" align="center" prop="bizNo" width="200" /> - <el-table-column - label="鍑哄叆搴撴棩鏈�" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="鍑哄叆搴撴暟閲�" - align="center" - prop="count" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column - label="搴撳瓨閲�" - align="center" - prop="totalCount" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column label="鎿嶄綔浜�" align="center" prop="creatorName" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { erpCountTableColumnFormatter } from '@/utils' - -/** ERP 浜у搧搴撳瓨鏄庣粏鍒楄〃 */ -defineOptions({ name: 'ErpStockRecord' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockRecordVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - productId: undefined, - warehouseId: undefined, - bizType: undefined, - bizNo: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockRecordApi.getStockRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockRecordApi.deleteStockRecord(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockRecordApi.exportStockRecord(queryParams) - download.excel(data, '浜у搧搴撳瓨鏄庣粏.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onActivated(() => { - getList() -}) - -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛� - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() -}) -</script> diff --git a/src/views/erp/stock/stock/index.vue b/src/views/erp/stock/stock/index.vue deleted file mode 100644 index 4d80117..0000000 --- a/src/views/erp/stock/stock/index.vue +++ /dev/null @@ -1,186 +0,0 @@ -<!-- ERP 浜у搧搴撳瓨鍒楄〃 --> -<template> - <doc-alert title="銆愬簱瀛樸�戜骇鍝佸簱瀛樸�佸簱瀛樻槑缁�" url="https://doc.iocoder.cn/erp/stock/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="浜у搧" prop="productId"> - <el-select - v-model="queryParams.productId" - clearable - filterable - placeholder="璇烽�夋嫨浜у搧" - class="!w-240px" - > - <el-option - v-for="item in productList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="浠撳簱" prop="warehouseId"> - <el-select - v-model="queryParams.warehouseId" - clearable - filterable - placeholder="璇烽�夋嫨浠撳簱" - class="!w-240px" - > - <el-option - v-for="item in warehouseList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:stock:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:stock:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="浜у搧鍚嶇О" align="center" prop="productName" /> - <el-table-column label="浜у搧鍗曚綅" align="center" prop="unitName" /> - <el-table-column label="浜у搧鍒嗙被" align="center" prop="categoryName" /> - <el-table-column - label="搴撳瓨閲�" - align="center" - prop="count" - :formatter="erpCountTableColumnFormatter" - /> - <el-table-column label="浠撳簱" align="center" prop="warehouseName" /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import download from '@/utils/download' -import { StockApi, StockVO } from '@/api/erp/stock/stock' -import { ProductApi, ProductVO } from '@/api/erp/product/product' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { erpCountTableColumnFormatter } from '@/utils' - -/** ERP 浜у搧搴撳瓨鍒楄〃 */ -defineOptions({ name: 'ErpStock' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<StockVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - productId: undefined, - warehouseId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const productList = ref<ProductVO[]>([]) // 浜у搧鍒楄〃 -const warehouseList = ref<WarehouseVO[]>([]) // 浠撳簱鍒楄〃 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await StockApi.getStockPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await StockApi.deleteStock(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await StockApi.exportStock(queryParams) - download.excel(data, '浜у搧搴撳瓨.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鍔犺浇浜у搧銆佷粨搴撳垪琛� - productList.value = await ProductApi.getProductSimpleList() - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() -}) -</script> diff --git a/src/views/erp/stock/warehouse/WarehouseForm.vue b/src/views/erp/stock/warehouse/WarehouseForm.vue deleted file mode 100644 index ea88a18..0000000 --- a/src/views/erp/stock/warehouse/WarehouseForm.vue +++ /dev/null @@ -1,157 +0,0 @@ -<!-- ERP 浠撳簱琛ㄥ崟 --> -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="浠撳簱鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ヤ粨搴撳悕绉�" /> - </el-form-item> - <el-form-item label="浠撳簱鍦板潃" prop="address"> - <el-input v-model="formData.address" placeholder="璇疯緭鍏ヤ粨搴撳湴鍧�" /> - </el-form-item> - <el-form-item label="浠撳簱鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="浠撳偍璐�" prop="warehousePrice"> - <el-input-number - v-model="formData.warehousePrice" - placeholder="璇疯緭鍏ヤ粨鍌ㄨ垂锛屽崟浣嶏細鍏�/澶�/KG" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - <el-form-item label="鎼繍璐�" prop="truckagePrice"> - <el-input-number - v-model="formData.truckagePrice" - placeholder="璇疯緭鍏ユ惉杩愯垂锛屽崟浣嶏細鍏�" - :min="0" - :precision="2" - class="!w-1/1" - /> - </el-form-item> - <el-form-item label="璐熻矗浜�" prop="principal"> - <el-input v-model="formData.principal" placeholder="璇疯緭鍏ヨ礋璐d汉" /> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number - v-model="formData.sort" - placeholder="璇疯緭鍏ユ帓搴�" - :precision="0" - class="!w-1/1" - /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input type="textarea" v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import { CommonStatusEnum } from '@/utils/constants' - -/** ERP 浠撳簱琛ㄥ崟 */ -defineOptions({ name: 'WarehouseForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - address: undefined, - sort: undefined, - remark: undefined, - principal: undefined, - warehousePrice: undefined, - truckagePrice: undefined, - status: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '浠撳簱鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await WarehouseApi.getWarehouse(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as WarehouseVO - if (formType.value === 'create') { - await WarehouseApi.createWarehouse(data) - message.success(t('common.createSuccess')) - } else { - await WarehouseApi.updateWarehouse(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - address: undefined, - sort: undefined, - remark: undefined, - principal: undefined, - warehousePrice: undefined, - truckagePrice: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/erp/stock/warehouse/index.vue b/src/views/erp/stock/warehouse/index.vue deleted file mode 100644 index 40bdebe..0000000 --- a/src/views/erp/stock/warehouse/index.vue +++ /dev/null @@ -1,242 +0,0 @@ -<!-- ERP 浠撳簱鍒楄〃 --> -<template> - <doc-alert title="銆愬簱瀛樸�戜骇鍝佸簱瀛樸�佸簱瀛樻槑缁�" url="https://doc.iocoder.cn/erp/stock/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="浠撳簱鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ヤ粨搴撳悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="浠撳簱鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨浠撳簱鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['erp:warehouse:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['erp:warehouse:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="浠撳簱鍚嶇О" align="center" prop="name" /> - <el-table-column label="浠撳簱鍦板潃" align="center" prop="address" /> - <el-table-column - label="浠撳偍璐�" - align="center" - prop="warehousePrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column - label="鎼繍璐�" - align="center" - prop="truckagePrice" - :formatter="erpPriceTableColumnFormatter" - /> - <el-table-column label="璐熻矗浜�" align="center" prop="principal" /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鏄惁榛樿" align="center" prop="defaultStatus"> - <template #default="scope"> - <el-switch - v-model="scope.row.defaultStatus" - :active-value="true" - :inactive-value="false" - @change="handleDefaultStatusChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['erp:warehouse:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['erp:warehouse:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <WarehouseForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' -import WarehouseForm from './WarehouseForm.vue' -import { erpPriceTableColumnFormatter } from '@/utils' - -/** ERP 浠撳簱鍒楄〃 */ -defineOptions({ name: 'ErpWarehouse' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<WarehouseVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await WarehouseApi.getWarehousePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await WarehouseApi.deleteWarehouse(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 淇敼榛樿鐘舵�� */ -const handleDefaultStatusChange = async (row: WarehouseVO) => { - try { - // 淇敼鐘舵�佺殑浜屾纭 - const text = row.defaultStatus ? '璁剧疆' : '鍙栨秷' - await message.confirm('纭瑕�' + text + '"' + row.name + '"榛樿鍚�?') - // 鍙戣捣淇敼鐘舵�� - await WarehouseApi.updateWarehouseDefaultStatus(row.id, row.defaultStatus) - // 鍒锋柊鍒楄〃 - await getList() - } catch (e) { - // 鍙栨秷鍚庯紝杩涜鎭㈠鎸夐挳 - row.defaultStatus = !row.defaultStatus - } -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await WarehouseApi.exportWarehouse(queryParams) - download.excel(data, '浠撳簱.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/home/components/ComparisonCard.vue b/src/views/mall/home/components/ComparisonCard.vue deleted file mode 100644 index ee1c2f0..0000000 --- a/src/views/mall/home/components/ComparisonCard.vue +++ /dev/null @@ -1,42 +0,0 @@ -<template> - <div class="flex flex-col gap-2 bg-[var(--el-bg-color-overlay)] p-6"> - <div class="flex items-center justify-between text-gray-500"> - <span>{{ title }}</span> - <el-tag>{{ tag }}</el-tag> - </div> - <div class="flex flex-row items-baseline justify-between"> - <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" class="text-3xl" /> - <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'"> - {{ Math.abs(toNumber(percent)) }}% - <Icon :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" class="!text-sm" /> - </span> - </div> - <el-divider class="mb-1! mt-2!" /> - <div class="flex flex-row items-center justify-between text-sm"> - <span class="text-gray-500">鏄ㄦ棩鏁版嵁</span> - <span>{{ prefix || '' }}{{ reference }}</span> - </div> - </div> -</template> -<script lang="ts" setup> -import { propTypes } from '@/utils/propTypes' -import { toNumber } from 'lodash-es' -import { calculateRelativeRate } from '@/utils' - -/** 浜ゆ槗瀵圭収鍗$墖 */ -defineOptions({ name: 'ComparisonCard' }) - -const props = defineProps({ - title: propTypes.string.def('').isRequired, - tag: propTypes.string.def(''), - prefix: propTypes.string.def(''), - value: propTypes.number.def(0).isRequired, - reference: propTypes.number.def(0).isRequired, - decimals: propTypes.number.def(0) -}) - -// 璁$畻鐜瘮 -const percent = computed(() => - calculateRelativeRate(props.value as number, props.reference as number) -) -</script> diff --git a/src/views/mall/home/components/MemberStatisticsCard.vue b/src/views/mall/home/components/MemberStatisticsCard.vue deleted file mode 100644 index 2f9d7ab..0000000 --- a/src/views/mall/home/components/MemberStatisticsCard.vue +++ /dev/null @@ -1,91 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <CardTitle title="鐢ㄦ埛缁熻" /> - </template> - <!-- 鎶樼嚎鍥� --> - <Echart :height="300" :options="lineChartOptions" /> - </el-card> -</template> -<script lang="ts" setup> -import dayjs from 'dayjs' -import { EChartsOption } from 'echarts' -import * as MemberStatisticsApi from '@/api/mall/statistics/member' -import { formatDate } from '@/utils/formatTime' -import { CardTitle } from '@/components/Card' - -/** 浼氬憳鐢ㄦ埛缁熻鍗$墖 */ -defineOptions({ name: 'MemberStatisticsCard' }) - -const loading = ref(true) // 鍔犺浇涓� -/** 鎶樼嚎鍥鹃厤缃� */ -const lineChartOptions = reactive<EChartsOption>({ - dataset: { - dimensions: ['date', 'count'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - top: 80, - containLabel: true - }, - legend: { - top: 50 - }, - series: [{ name: '娉ㄥ唽閲�', type: 'line', smooth: true, areaStyle: {} }], - toolbox: { - feature: { - // 鏁版嵁鍖哄煙缂╂斁 - dataZoom: { - yAxisIndex: false // Y杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '浼氬憳缁熻' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross' - }, - padding: [5, 10] - }, - xAxis: { - type: 'category', - boundaryGap: false, - axisTick: { - show: false - }, - axisLabel: { - formatter: (date: string) => formatDate(date, 'MM-DD') - } - }, - yAxis: { - axisTick: { - show: false - } - } -}) as EChartsOption - -const getMemberRegisterCountList = async () => { - loading.value = true - // 鏌ヨ鏈�杩戜竴鏈堟暟鎹� - const beginTime = dayjs().subtract(30, 'd').startOf('d') - const endTime = dayjs().endOf('d') - const list = await MemberStatisticsApi.getMemberRegisterCountList(beginTime, endTime) - // 鏇存柊 Echarts 鏁版嵁 - if (lineChartOptions.dataset && lineChartOptions.dataset['source']) { - lineChartOptions.dataset['source'] = list - } - loading.value = false -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getMemberRegisterCountList() -}) -</script> diff --git a/src/views/mall/home/components/OperationDataCard.vue b/src/views/mall/home/components/OperationDataCard.vue deleted file mode 100644 index b905203..0000000 --- a/src/views/mall/home/components/OperationDataCard.vue +++ /dev/null @@ -1,92 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <CardTitle title="杩愯惀鏁版嵁" /> - </template> - <div class="flex flex-row flex-wrap items-center gap-8 p-4"> - <div - v-for="item in data" - :key="item.name" - class="h-20 w-20% flex flex-col cursor-pointer items-center justify-center gap-2" - @click="handleClick(item.routerName)" - > - <CountTo - :prefix="item.prefix" - :end-val="item.value" - :decimals="item.decimals" - class="text-3xl" - /> - <span class="text-center">{{ item.name }}</span> - </div> - </div> - </el-card> -</template> -<script lang="ts" setup> -import * as ProductSpuApi from '@/api/mall/product/spu' -import * as TradeStatisticsApi from '@/api/mall/statistics/trade' -import * as PayStatisticsApi from '@/api/mall/statistics/pay' -import { CardTitle } from '@/components/Card' - -/** 杩愯惀鏁版嵁鍗$墖 */ -defineOptions({ name: 'OperationDataCard' }) - -const router = useRouter() // 璺敱 - -/** 鏁版嵁 */ -const data = reactive({ - orderUndelivered: { name: '寰呭彂璐ц鍗�', value: 9, routerName: 'TradeOrder' }, - orderAfterSaleApply: { name: '閫�娆句腑璁㈠崟', value: 4, routerName: 'TradeAfterSale' }, - orderWaitePickUp: { name: '寰呮牳閿�璁㈠崟', value: 0, routerName: 'TradeOrder' }, - productAlertStock: { name: '搴撳瓨棰勮', value: 0, routerName: 'ProductSpu' }, - productForSale: { name: '涓婃灦鍟嗗搧', value: 0, routerName: 'ProductSpu' }, - productInWarehouse: { name: '浠撳簱鍟嗗搧', value: 0, routerName: 'ProductSpu' }, - withdrawAuditing: { name: '鎻愮幇寰呭鏍�', value: 0, routerName: 'TradeBrokerageWithdraw' }, - rechargePrice: { - name: '璐︽埛鍏呭��', - value: 0.0, - prefix: '锟�', - decimals: 2, - routerName: 'PayWalletRecharge' - } -}) - -/** 鏌ヨ璁㈠崟鏁版嵁 */ -const getOrderData = async () => { - const orderCount = await TradeStatisticsApi.getOrderCount() - data.orderUndelivered.value = orderCount.undelivered - data.orderAfterSaleApply.value = orderCount.afterSaleApply - data.orderWaitePickUp.value = orderCount.pickUp - data.withdrawAuditing.value = orderCount.auditingWithdraw -} - -/** 鏌ヨ鍟嗗搧鏁版嵁 */ -const getProductData = async () => { - // TODO: @鑺嬭壙锛氳繖涓帴鍙g殑杩斿洖鍊硷紝鏄笉鏄敤鍛藉悕瀛楁鏇村ソ浜涳紵 - const productCount = await ProductSpuApi.getTabsCount() - data.productForSale.value = productCount['0'] - data.productInWarehouse.value = productCount['1'] - data.productAlertStock.value = productCount['3'] -} - -/** 鏌ヨ閽卞寘鍏呭�兼暟鎹� */ -const getWalletRechargeData = async () => { - const paySummary = await PayStatisticsApi.getWalletRechargePrice() - data.rechargePrice.value = paySummary.rechargePrice -} - -/** - * 璺宠浆鍒板搴旈〉闈� - * - * @param routerName 璺敱椤甸潰缁勪欢鐨勫悕绉� - */ -const handleClick = (routerName: string) => { - router.push({ name: routerName }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getOrderData() - getProductData() - getWalletRechargeData() -}) -</script> diff --git a/src/views/mall/home/components/ShortcutCard.vue b/src/views/mall/home/components/ShortcutCard.vue deleted file mode 100644 index cea9113..0000000 --- a/src/views/mall/home/components/ShortcutCard.vue +++ /dev/null @@ -1,82 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <CardTitle title="蹇嵎鍏ュ彛" /> - </template> - <div class="flex flex-row flex-wrap gap-8 p-4"> - <div - v-for="menu in menuList" - :key="menu.name" - class="h-20 w-20% flex flex-col cursor-pointer items-center justify-center gap-2" - @click="handleMenuClick(menu.routerName)" - > - <div - :class="menu.bgColor" - class="h-48px w-48px flex items-center justify-center rounded text-white" - > - <Icon :icon="menu.icon" class="text-7.5!" /> - </div> - <span>{{ menu.name }}</span> - </div> - </div> - </el-card> -</template> -<script lang="ts" setup> -/** 蹇嵎鍏ュ彛鍗$墖 */ -import { CardTitle } from '@/components/Card' - -defineOptions({ name: 'ShortcutCard' }) - -const router = useRouter() // 璺敱 - -/** 鑿滃崟鍒楄〃 */ -const menuList = [ - { name: '鐢ㄦ埛绠$悊', icon: 'ep:user-filled', bgColor: 'bg-red-400', routerName: 'MemberUser' }, - { - name: '鍟嗗搧绠$悊', - icon: 'fluent-mdl2:product', - bgColor: 'bg-orange-400', - routerName: 'ProductSpu' - }, - { name: '璁㈠崟绠$悊', icon: 'ep:list', bgColor: 'bg-yellow-500', routerName: 'TradeOrder' }, - { - name: '鍞悗绠$悊', - icon: 'ri:refund-2-line', - bgColor: 'bg-green-600', - routerName: 'TradeAfterSale' - }, - { - name: '鍒嗛攢绠$悊', - icon: 'fa-solid:project-diagram', - bgColor: 'bg-cyan-500', - routerName: 'TradeBrokerageUser' - }, - { - name: '浼樻儬鍒�', - icon: 'ep:ticket', - bgColor: 'bg-blue-500', - routerName: 'PromotionCoupon' - }, - { - name: '鎷煎洟娲诲姩', - icon: 'fa:group', - bgColor: 'bg-purple-500', - routerName: 'PromotionBargainActivity' - }, - { - name: '浣i噾鎻愮幇', - icon: 'vaadin:money-withdraw', - bgColor: 'bg-rose-500', - routerName: 'TradeBrokerageWithdraw' - } -] - -/** - * 璺宠浆鍒拌彍鍗曞搴旈〉闈� - * - * @param routerName 璺敱椤甸潰缁勪欢鐨勫悕绉� - */ -const handleMenuClick = (routerName: string) => { - router.push({ name: routerName }) -} -</script> diff --git a/src/views/mall/home/components/TradeTrendCard.vue b/src/views/mall/home/components/TradeTrendCard.vue deleted file mode 100644 index 7930e21..0000000 --- a/src/views/mall/home/components/TradeTrendCard.vue +++ /dev/null @@ -1,208 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <div class="flex flex-row items-center justify-between"> - <CardTitle title="浜ゆ槗閲忚秼鍔�" /> - <!-- 鏌ヨ鏉′欢 --> - <div class="flex flex-row items-center gap-2"> - <el-radio-group v-model="timeRangeType" @change="handleTimeRangeTypeChange"> - <el-radio-button v-for="[key, value] in timeRange.entries()" :key="key" :label="key"> - {{ value.name }} - </el-radio-button> - </el-radio-group> - </div> - </div> - </template> - <!-- 鎶樼嚎鍥� --> - <Echart :height="300" :options="eChartOptions" /> - </el-card> -</template> -<script lang="ts" setup> -import dayjs, { Dayjs } from 'dayjs' -import { EChartsOption } from 'echarts' -import * as TradeStatisticsApi from '@/api/mall/statistics/trade' -import { fenToYuan } from '@/utils' -import { formatDate } from '@/utils/formatTime' -import { CardTitle } from '@/components/Card' - -/** 浜ゆ槗閲忚秼鍔� */ -defineOptions({ name: 'TradeTrendCard' }) - -enum TimeRangeTypeEnum { - DAY30 = 1, - WEEK = 7, - MONTH = 30, - YEAR = 365 -} // 鏃ユ湡绫诲瀷 -const timeRangeType = ref(TimeRangeTypeEnum.DAY30) // 鏃ユ湡蹇嵎閫夋嫨鎸夐挳, 榛樿30澶� -const loading = ref(true) // 鍔犺浇涓� -// 鏃堕棿鑼冨洿 Map -const timeRange = new Map() - .set(TimeRangeTypeEnum.DAY30, { - name: '30澶�', - series: [ - { name: '璁㈠崟閲戦', type: 'bar', smooth: true, data: [] }, - { name: '璁㈠崟鏁伴噺', type: 'line', smooth: true, data: [] } - ] - }) - .set(TimeRangeTypeEnum.WEEK, { - name: '鍛�', - series: [ - { name: '涓婂懆閲戦', type: 'bar', smooth: true, data: [] }, - { name: '鏈懆閲戦', type: 'bar', smooth: true, data: [] }, - { name: '涓婂懆鏁伴噺', type: 'line', smooth: true, data: [] }, - { name: '鏈懆鏁伴噺', type: 'line', smooth: true, data: [] } - ] - }) - .set(TimeRangeTypeEnum.MONTH, { - name: '鏈�', - series: [ - { name: '涓婃湀閲戦', type: 'bar', smooth: true, data: [] }, - { name: '鏈湀閲戦', type: 'bar', smooth: true, data: [] }, - { name: '涓婃湀鏁伴噺', type: 'line', smooth: true, data: [] }, - { name: '鏈湀鏁伴噺', type: 'line', smooth: true, data: [] } - ] - }) - .set(TimeRangeTypeEnum.YEAR, { - name: '骞�', - series: [ - { name: '鍘诲勾閲戦', type: 'bar', smooth: true, data: [] }, - { name: '浠婂勾閲戦', type: 'bar', smooth: true, data: [] }, - { name: '鍘诲勾鏁伴噺', type: 'line', smooth: true, data: [] }, - { name: '浠婂勾鏁伴噺', type: 'line', smooth: true, data: [] } - ] - }) -/** 鍥捐〃閰嶇疆 */ -const eChartOptions = reactive<EChartsOption>({ - grid: { - left: 20, - right: 20, - bottom: 20, - top: 80, - containLabel: true - }, - legend: { - top: 50, - data: [] - }, - series: [], - toolbox: { - feature: { - // 鏁版嵁鍖哄煙缂╂斁 - dataZoom: { - yAxisIndex: false // Y杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '璁㈠崟閲忚秼鍔�' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross' - }, - padding: [5, 10] - }, - xAxis: { - type: 'category', - inverse: true, - boundaryGap: false, - axisTick: { - show: false - }, - data: [], - axisLabel: { - formatter: (date: string) => { - switch (timeRangeType.value) { - case TimeRangeTypeEnum.DAY30: - return formatDate(date, 'MM-DD') - case TimeRangeTypeEnum.WEEK: - let weekDay = formatDate(date, 'ddd') - if (weekDay == '0') weekDay = '鏃�' - return '鍛�' + weekDay - case TimeRangeTypeEnum.MONTH: - return formatDate(date, 'D') - case TimeRangeTypeEnum.YEAR: - return formatDate(date, 'M') + '鏈�' - default: - return date - } - } - } - }, - yAxis: { - axisTick: { - show: false - } - } -}) as EChartsOption - -/** 鏃堕棿鑼冨洿绫诲瀷鍗曢�夋寜閽�変腑 */ -const handleTimeRangeTypeChange = async () => { - // 璁剧疆鏃堕棿鑼冨洿 - let beginTime: Dayjs - let endTime: Dayjs - switch (timeRangeType.value) { - case TimeRangeTypeEnum.WEEK: - beginTime = dayjs().startOf('week') - endTime = dayjs().endOf('week') - break - case TimeRangeTypeEnum.MONTH: - beginTime = dayjs().startOf('month') - endTime = dayjs().endOf('month') - break - case TimeRangeTypeEnum.YEAR: - beginTime = dayjs().startOf('year') - endTime = dayjs().endOf('year') - break - case TimeRangeTypeEnum.DAY30: - default: - beginTime = dayjs().subtract(30, 'day').startOf('d') - endTime = dayjs().endOf('d') - break - } - // 鍙戦�佹椂闂磋寖鍥撮�変腑浜嬩欢 - await getOrderCountTrendComparison(beginTime, endTime) -} - -/** 鏌ヨ璁㈠崟鏁伴噺瓒嬪娍瀵圭収鏁版嵁 */ -const getOrderCountTrendComparison = async ( - beginTime: dayjs.ConfigType, - endTime: dayjs.ConfigType -) => { - loading.value = true - // 鏌ヨ鏁版嵁 - const list = await TradeStatisticsApi.getOrderCountTrendComparison( - timeRangeType.value, - beginTime, - endTime - ) - // 澶勭悊鏁版嵁 - const dates: string[] = [] - const series = [...timeRange.get(timeRangeType.value).series] - for (let item of list) { - dates.push(item.value.date) - if (series.length === 2) { - series[0].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 褰撳墠閲戦 - series[1].data.push(item?.value?.orderPayCount || 0) // 褰撳墠鏁伴噺 - } else { - series[0].data.push(fenToYuan(item?.reference?.orderPayPrice || 0)) // 瀵圭収閲戦 - series[1].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 褰撳墠閲戦 - series[2].data.push(item?.reference?.orderPayCount || 0) // 瀵圭収鏁伴噺 - series[3].data.push(item?.value?.orderPayCount || 0) // 褰撳墠鏁伴噺 - } - } - eChartOptions.xAxis!['data'] = dates - eChartOptions.series = series - // legend鍦�4涓垏鎹㈠埌2涓殑鏃跺�欙紝杩樻槸鏄剧ず鎴�4涓紝闇�瑕佹墜鍔ㄩ厤缃竴涓� - eChartOptions.legend['data'] = series.map((item) => item.name) - loading.value = false -} - -/** 鍒濆鍖� **/ -onMounted(() => { - handleTimeRangeTypeChange() -}) -</script> diff --git a/src/views/mall/home/index.vue b/src/views/mall/home/index.vue deleted file mode 100644 index 89baf33..0000000 --- a/src/views/mall/home/index.vue +++ /dev/null @@ -1,113 +0,0 @@ -<template> - <doc-alert title="鍟嗗煄鎵嬪唽锛堝姛鑳藉紑鍚級" url="https://doc.iocoder.cn/mall/build/" /> - - <div class="flex flex-col"> - <!-- 鏁版嵁瀵圭収 --> - <el-row :gutter="16" class="row"> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <ComparisonCard - tag="浠婃棩" - title="閿�鍞" - prefix="锟�" - :decimals="2" - :value="fenToYuan(orderComparison?.value?.orderPayPrice || 0)" - :reference="fenToYuan(orderComparison?.reference?.orderPayPrice || 0)" - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <ComparisonCard - tag="浠婃棩" - title="鐢ㄦ埛璁块棶閲�" - :value="userComparison?.value?.visitUserCount || 0" - :reference="userComparison?.reference?.visitUserCount || 0" - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <ComparisonCard - tag="浠婃棩" - title="璁㈠崟閲�" - :value="orderComparison?.value?.orderPayCount || 0" - :reference="orderComparison?.reference?.orderPayCount || 0" - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24" :loading="loading"> - <ComparisonCard - tag="浠婃棩" - title="鏂板鐢ㄦ埛" - :value="userComparison?.value?.registerUserCount || 0" - :reference="userComparison?.reference?.registerUserCount || 0" - /> - </el-col> - </el-row> - <el-row :gutter="16" class="row"> - <el-col :md="12"> - <!-- 蹇嵎鍏ュ彛 --> - <ShortcutCard /> - </el-col> - <el-col :md="12"> - <!-- 杩愯惀鏁版嵁 --> - <OperationDataCard /> - </el-col> - </el-row> - <el-row :gutter="16" class="mb-4"> - <el-col :md="18" :sm="24"> - <!-- 浼氬憳姒傝 --> - <MemberFunnelCard /> - </el-col> - <el-col :md="6" :sm="24"> - <!-- 浼氬憳缁堢 --> - <MemberTerminalCard /> - </el-col> - </el-row> - <!-- 浜ゆ槗閲忚秼鍔� --> - <TradeTrendCard class="mb-4" /> - <!-- 浼氬憳缁熻 --> - <MemberStatisticsCard /> - </div> -</template> -<script lang="ts" setup> -import * as TradeStatisticsApi from '@/api/mall/statistics/trade' -import * as MemberStatisticsApi from '@/api/mall/statistics/member' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' -import { TradeOrderSummaryRespVO } from '@/api/mall/statistics/trade' -import { MemberCountRespVO } from '@/api/mall/statistics/member' -import { fenToYuan } from '@/utils' -import ComparisonCard from './components/ComparisonCard.vue' -import MemberStatisticsCard from './components/MemberStatisticsCard.vue' -import OperationDataCard from './components/OperationDataCard.vue' -import ShortcutCard from './components/ShortcutCard.vue' -import TradeTrendCard from './components/TradeTrendCard.vue' -import MemberTerminalCard from '@/views/mall/statistics/member/components/MemberTerminalCard.vue' -import MemberFunnelCard from '@/views/mall/statistics/member/components/MemberFunnelCard.vue' - -/** 鍟嗗煄棣栭〉 */ -defineOptions({ name: 'MallHome' }) - -const loading = ref(true) // 鍔犺浇涓� -const orderComparison = ref<DataComparisonRespVO<TradeOrderSummaryRespVO>>() // 浜ゆ槗瀵圭収鏁版嵁 -const userComparison = ref<DataComparisonRespVO<MemberCountRespVO>>() // 鐢ㄦ埛瀵圭収鏁版嵁 - -/** 鏌ヨ浜ゆ槗瀵圭収鍗$墖鏁版嵁 */ -const getOrderComparison = async () => { - orderComparison.value = await TradeStatisticsApi.getOrderComparison() -} - -/** 鏌ヨ浼氬憳鐢ㄦ埛鏁伴噺瀵圭収鍗$墖鏁版嵁 */ -const getUserCountComparison = async () => { - userComparison.value = await MemberStatisticsApi.getUserCountComparison() -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - loading.value = true - await Promise.all([getOrderComparison(), getUserCountComparison()]) - loading.value = false -}) -</script> -<style lang="scss" scoped> -.row { - .el-col { - margin-bottom: 1rem; - } -} -</style> diff --git a/src/views/mall/product/brand/BrandForm.vue b/src/views/mall/product/brand/BrandForm.vue deleted file mode 100644 index ab34737..0000000 --- a/src/views/mall/product/brand/BrandForm.vue +++ /dev/null @@ -1,123 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="80px" - v-loading="formLoading" - > - <el-form-item label="鍝佺墝鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ搧鐗屽悕绉�" /> - </el-form-item> - <el-form-item label="鍝佺墝鍥剧墖" prop="picUrl"> - <UploadImg v-model="formData.picUrl" :limit="1" :is-show-tip="false" /> - </el-form-item> - <el-form-item label="鍝佺墝鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" controls-position="right" :min="0" /> - </el-form-item> - <el-form-item label="鍝佺墝鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鍝佺墝鎻忚堪"> - <el-input v-model="formData.description" type="textarea" placeholder="璇疯緭鍏ュ搧鐗屾弿杩�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import * as ProductBrandApi from '@/api/mall/product/brand' - -defineOptions({ name: 'ProductBrandForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '', - picUrl: '', - status: CommonStatusEnum.ENABLE, - description: '' -}) -const formRules = reactive({ - name: [{ required: true, message: '鍝佺墝鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - picUrl: [{ required: true, message: '鍝佺墝鍥剧墖涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鍝佺墝鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductBrandApi.getBrand(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as ProductBrandApi.BrandVO - if (formType.value === 'create') { - await ProductBrandApi.createBrand(data) - message.success(t('common.createSuccess')) - } else { - await ProductBrandApi.updateBrand(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - picUrl: '', - status: CommonStatusEnum.ENABLE, - description: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/brand/index.vue b/src/views/mall/product/brand/index.vue deleted file mode 100644 index 3e34b93..0000000 --- a/src/views/mall/product/brand/index.vue +++ /dev/null @@ -1,182 +0,0 @@ -<template> - <doc-alert title="鍟嗗煄鎵嬪唽锛堝姛鑳藉紑鍚級" url="https://doc.iocoder.cn/mall/build/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍝佺墝鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ搧鐗屽悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['product:brand:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" row-key="id" default-expand-all> - <el-table-column label="鍝佺墝鍚嶇О" prop="name" sortable /> - <el-table-column label="鍝佺墝鍥剧墖" align="center" prop="picUrl"> - <template #default="scope"> - <img v-if="scope.row.picUrl" :src="scope.row.picUrl" alt="鍝佺墝鍥剧墖" class="h-30px" /> - </template> - </el-table-column> - <el-table-column label="鍝佺墝鎺掑簭" align="center" prop="sort" /> - <el-table-column label="寮�鍚姸鎬�" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['product:brand:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['product:brand:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BrandForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as ProductBrandApi from '@/api/mall/product/brand' -import BrandForm from './BrandForm.vue' - -defineOptions({ name: 'ProductBrand' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductBrandApi.getBrandParam(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductBrandApi.deleteBrand(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/product/category/CategoryForm.vue b/src/views/mall/product/category/CategoryForm.vue deleted file mode 100644 index 7f20927..0000000 --- a/src/views/mall/product/category/CategoryForm.vue +++ /dev/null @@ -1,135 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="涓婄骇鍒嗙被" prop="parentId"> - <el-select v-model="formData.parentId" placeholder="璇烽�夋嫨涓婄骇鍒嗙被"> - <el-option :key="0" label="椤剁骇鍒嗙被" :value="0" /> - <el-option - v-for="item in categoryList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒嗙被鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ垎绫诲悕绉�" /> - </el-form-item> - <el-form-item label="绉诲姩绔垎绫诲浘" prop="picUrl"> - <UploadImg v-model="formData.picUrl" :limit="1" :is-show-tip="false" /> - <div style="font-size: 10px" class="pl-10px">鎺ㄨ崘 180x180 鍥剧墖鍒嗚鲸鐜�</div> - </el-form-item> - <el-form-item label="鍒嗙被鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" controls-position="right" :min="0" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import * as ProductCategoryApi from '@/api/mall/product/category' - -defineOptions({ name: 'ProductCategory' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '', - picUrl: '', - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - parentId: [{ required: true, message: '璇烽�夋嫨涓婄骇鍒嗙被', trigger: 'blur' }], - name: [{ required: true, message: '鍒嗙被鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - picUrl: [{ required: true, message: '鍒嗙被鍥剧墖涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鍒嗙被鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const categoryList = ref<any[]>([]) // 鍒嗙被鏍� - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ProductCategoryApi.getCategory(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱鍒嗙被鏍� - categoryList.value = await ProductCategoryApi.getCategoryList({ parentId: 0 }) -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as ProductCategoryApi.CategoryVO - if (formType.value === 'create') { - await ProductCategoryApi.createCategory(data) - message.success(t('common.createSuccess')) - } else { - await ProductCategoryApi.updateCategory(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - picUrl: '', - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/category/components/ProductCategorySelect.vue b/src/views/mall/product/category/components/ProductCategorySelect.vue deleted file mode 100644 index c1810f5..0000000 --- a/src/views/mall/product/category/components/ProductCategorySelect.vue +++ /dev/null @@ -1,51 +0,0 @@ -<template> - <el-tree-select - v-model="selectCategoryId" - :data="categoryList" - :props="defaultProps" - :multiple="multiple" - :show-checkbox="multiple" - class="w-1/1" - node-key="id" - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - /> -</template> -<script lang="ts" setup> -import { defaultProps, handleTree } from '@/utils/tree' -import * as ProductCategoryApi from '@/api/mall/product/category' -import { oneOfType } from 'vue-types' -import { propTypes } from '@/utils/propTypes' - -/** 鍟嗗搧鍒嗙被閫夋嫨缁勪欢 */ -defineOptions({ name: 'ProductCategorySelect' }) - -const props = defineProps({ - // 閫変腑鐨処D - modelValue: oneOfType<number | number[]>([Number, Array<Number>]), - // 鏄惁澶氶�� - multiple: propTypes.bool.def(false), - // 涓婄骇鍝佺被鐨勭紪鍙� - parentId: propTypes.number.def(undefined) -}) - -/** 閫変腑鐨勫垎绫� ID */ -const selectCategoryId = computed({ - get: () => { - return props.modelValue - }, - set: (val: number | number[]) => { - emit('update:modelValue', val) - } -}) - -/** 鍒嗙被閫夋嫨 */ -const emit = defineEmits(['update:modelValue']) - -/** 鍒濆鍖� **/ -const categoryList = ref<ProductCategoryApi.CategoryVO[]>([]) // 鍒嗙被鏍� -onMounted(async () => { - // 鑾峰緱鍒嗙被鏍� - const data = await ProductCategoryApi.getCategoryList({ parentId: props.parentId }) - categoryList.value = handleTree(data, 'id', 'parentId') -}) -</script> diff --git a/src/views/mall/product/category/index.vue b/src/views/mall/product/category/index.vue deleted file mode 100644 index b801cb2..0000000 --- a/src/views/mall/product/category/index.vue +++ /dev/null @@ -1,149 +0,0 @@ -<template> - <doc-alert title="銆愬晢鍝併�戝晢鍝佸垎绫�" url="https://doc.iocoder.cn/mall/product-category/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍒嗙被鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ垎绫诲悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['product:category:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" row-key="id" default-expand-all> - <el-table-column label="鍚嶇О" min-width="240" prop="name" sortable /> - <el-table-column label="鍒嗙被鍥炬爣" align="center" min-width="80" prop="picUrl"> - <template #default="scope"> - <img :src="scope.row.picUrl" alt="绉诲姩绔垎绫诲浘" class="h-36px" /> - </template> - </el-table-column> - <el-table-column label="鎺掑簭" align="center" min-width="150" prop="sort" /> - <el-table-column label="鐘舵��" align="center" min-width="150" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['product:category:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['product:category:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CategoryForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { handleTree } from '@/utils/tree' -import { dateFormatter } from '@/utils/formatTime' -import * as ProductCategoryApi from '@/api/mall/product/category' -import CategoryForm from './CategoryForm.vue' - -defineOptions({ name: 'ProductCategory' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - name: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductCategoryApi.getCategoryList(queryParams) - list.value = handleTree(data, 'id', 'parentId') - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductCategoryApi.deleteCategory(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/product/comment/CommentForm.vue b/src/views/mall/product/comment/CommentForm.vue deleted file mode 100644 index b8d700c..0000000 --- a/src/views/mall/product/comment/CommentForm.vue +++ /dev/null @@ -1,167 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="娣诲姞铏氭嫙璇勮"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="鍟嗗搧" prop="spuId"> - <SpuShowcase v-model="formData.spuId" :limit="1" /> - </el-form-item> - <el-form-item v-if="formData.spuId" label="鍟嗗搧瑙勬牸" prop="skuId"> - <div class="h-60px w-60px" @click="handleSelectSku"> - <div v-if="skuData && skuData.picUrl"> - <el-image :src="skuData.picUrl" /> - </div> - <div v-else class="select-box"> - <Icon icon="ep:plus" /> - </div> - </div> - </el-form-item> - <el-form-item label="鐢ㄦ埛澶村儚" prop="userAvatar"> - <UploadImg v-model="formData.userAvatar" height="60px" width="60px" /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userNickname"> - <el-input v-model="formData.userNickname" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" /> - </el-form-item> - <el-form-item label="璇勮鍐呭" prop="content"> - <el-input v-model="formData.content" type="textarea" /> - </el-form-item> - <el-form-item label="鎻忚堪鏄熺骇" prop="descriptionScores"> - <el-rate v-model="formData.descriptionScores" /> - </el-form-item> - <el-form-item label="鏈嶅姟鏄熺骇" prop="benefitScores"> - <el-rate v-model="formData.benefitScores" /> - </el-form-item> - <el-form-item label="璇勮鍥剧墖" prop="picUrls"> - <UploadImgs v-model="formData.picUrls" :limit="9" height="60px" width="60px" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SkuTableSelect ref="skuTableSelectRef" :spu-id="formData.spuId" @change="handleSkuChange" /> -</template> -<script lang="ts" setup> -import * as CommentApi from '@/api/mall/product/comment' -import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue' -import * as ProductSpuApi from '@/api/mall/product/spu' -import SkuTableSelect from '@/views/mall/product/spu/components/SkuTableSelect.vue' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - userId: undefined, - userNickname: undefined, - userAvatar: undefined, - spuId: 0, - skuId: undefined, - descriptionScores: 5, - benefitScores: 5, - content: undefined, - picUrls: [] -}) -const formRules = reactive({ - spuId: [{ required: true, message: '鍟嗗搧涓嶈兘涓虹┖', trigger: 'blur' }], - skuId: [{ required: true, message: '瑙勬牸涓嶈兘涓虹┖', trigger: 'blur' }], - userAvatar: [{ required: true, message: '鐢ㄦ埛澶村儚涓嶈兘涓虹┖', trigger: 'blur' }], - userNickname: [{ required: true, message: '鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - content: [{ required: true, message: '璇勮鍐呭涓嶈兘涓虹┖', trigger: 'blur' }], - descriptionScores: [{ required: true, message: '鎻忚堪鏄熺骇涓嶈兘涓虹┖', trigger: 'blur' }], - benefitScores: [{ required: true, message: '鏈嶅姟鏄熺骇涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const skuData = ref({ - id: -1, - name: '', - picUrl: '' -}) - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await CommentApi.getComment(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - if (formType.value === 'create') { - await CommentApi.createComment(unref(formData.value) as any) - message.success(t('common.createSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - userId: undefined, - userNickname: undefined, - userAvatar: undefined, - spuId: 0, - skuId: undefined, - descriptionScores: 5, - benefitScores: 5, - content: undefined, - picUrls: [] - } - formRef.value?.resetFields() -} - -/** SKU 琛ㄦ牸閫夋嫨 */ -const skuTableSelectRef = ref() -const handleSelectSku = () => { - skuTableSelectRef.value.open() -} -const handleSkuChange = (sku: ProductSpuApi.Sku) => { - skuData.value = sku - formData.value.skuId = sku.id -} -</script> -<style> -.select-box { - display: flex; - width: 100%; - height: 100%; - border: 1px dashed var(--el-border-color-darker); - border-radius: 8px; - align-items: center; - justify-content: center; -} -</style> diff --git a/src/views/mall/product/comment/ReplyForm.vue b/src/views/mall/product/comment/ReplyForm.vue deleted file mode 100644 index 4c8bd4d..0000000 --- a/src/views/mall/product/comment/ReplyForm.vue +++ /dev/null @@ -1,76 +0,0 @@ -<template> - <Dialog title="鍥炲" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍥炲鍐呭" prop="replyContent"> - <el-input type="textarea" v-model="formData.replyContent" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitReplyForm" type="primary" :disabled="formLoading">纭� 瀹� </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script setup lang="ts"> -import * as CommentApi from '@/api/mall/product/comment' -import { ElInput } from 'element-plus' - -defineOptions({ name: 'ProductComment' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - replyContent: undefined -}) -const formRules = reactive({ - replyContent: [{ required: true, message: '鍥炲鍐呭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (id?: number) => { - resetForm() - formData.value.id = id - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitReplyForm = async () => { - // 鏍¢獙琛ㄥ崟 - const valid = await formRef?.value?.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await CommentApi.replyComment(formData.value) - message.success(t('common.createSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - replyContent: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/comment/index.vue b/src/views/mall/product/comment/index.vue deleted file mode 100644 index 8854fdb..0000000 --- a/src/views/mall/product/comment/index.vue +++ /dev/null @@ -1,244 +0,0 @@ -<template> - <doc-alert title="銆愬晢鍝併�戝晢鍝佽瘎浠�" url="https://doc.iocoder.cn/mall/product-comment/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍥炲鐘舵��" prop="replyStatus"> - <el-select v-model="queryParams.replyStatus"> - <el-option label="宸插洖澶�" :value="true" /> - <el-option label="鏈洖澶�" :value="false" /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗗搧鍚嶇О" prop="spuName"> - <el-input v-model="queryParams.spuName" placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userNickname"> - <el-input v-model="queryParams.userNickname" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" /> - </el-form-item> - <el-form-item label="璁㈠崟缂栧彿" prop="orderId"> - <el-input v-model="queryParams.orderId" placeholder="璇疯緭鍏ヨ鍗曠紪鍙�" /> - </el-form-item> - <el-form-item label="璇勮鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 閲嶇疆 - </el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['product:comment:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> - 娣诲姞铏氭嫙璇勮 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="false"> - <el-table-column label="璇勮缂栧彿" align="center" prop="id" min-width="80" /> - <el-table-column label="鍟嗗搧淇℃伅" align="center" min-width="400"> - <template #default="scope"> - <div class="row flex items-center gap-x-4px"> - <el-image - v-if="scope.row.skuPicUrl" - :src="scope.row.skuPicUrl" - :preview-src-list="[scope.row.skuPicUrl]" - class="h-40px w-40px shrink-0" - preview-teleported - /> - <div>{{ scope.row.spuName }}</div> - <el-tag - v-for="property in scope.row.skuProperties" - :key="property.propertyId" - class="mr-10px" - > - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </div> - </template> - </el-table-column> - <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" prop="userNickname" width="100" /> - <el-table-column label="鍟嗗搧璇勫垎" align="center" prop="descriptionScores" width="90" /> - <el-table-column label="鏈嶅姟璇勫垎" align="center" prop="benefitScores" width="90" /> - <el-table-column label="璇勮鍐呭" align="center" prop="content" min-width="210"> - <template #default="scope"> - <p>{{ scope.row.content }}</p> - <div class="flex justify-center gap-x-4px"> - <el-image - v-for="(picUrl, index) in scope.row.picUrls" - :key="index" - :src="picUrl" - :preview-src-list="scope.row.picUrls" - :initial-index="index" - class="h-40px w-40px" - preview-teleported - /> - </div> - </template> - </el-table-column> - <el-table-column - label="鍥炲鍐呭" - align="center" - prop="replyContent" - min-width="250" - show-overflow-tooltip - /> - <el-table-column - label="璇勮鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column label="鏄惁灞曠ず" align="center" width="80px"> - <template #default="scope"> - <el-switch - v-model="scope.row.visible" - :active-value="true" - :inactive-value="false" - v-hasPermi="['product:comment:update']" - @change="handleVisibleChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" min-width="60px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="handleReply(scope.row.id)" - v-hasPermi="['product:comment:update']" - > - 鍥炲 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CommentForm ref="formRef" @success="getList" /> - <!-- 鍥炲琛ㄥ崟寮圭獥 --> - <ReplyForm ref="replyFormRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as CommentApi from '@/api/mall/product/comment' -import CommentForm from './CommentForm.vue' -import ReplyForm from './ReplyForm.vue' - -defineOptions({ name: 'ProductComment' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - replyStatus: null, - spuName: null, - userNickname: null, - orderId: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CommentApi.getCommentPage(queryParams) - // visible 濡傛灉涓� null锛屼細瀵艰嚧鍒锋柊鐨勬椂鍊欒Е鍙� e-switch 鐨� change 浜嬩欢 - data.list.forEach((item) => { - if (!item.visible) { - item.visible = false - } - }) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍥炲鎸夐挳鎿嶄綔 **/ -const replyFormRef = ref() -const handleReply = (id: number) => { - replyFormRef.value.open(id) -} - -/** 鏄剧ず/闅愯棌 **/ -const handleVisibleChange = async (row: CommentApi.CommentVO) => { - if (loading.value) { - return - } - let changedValue = row.visible - try { - await message.confirm(changedValue ? '鏄惁鏄剧ず璇勮锛�' : '鏄惁闅愯棌璇勮锛�') - await CommentApi.updateCommentVisible({ id: row.id, visible: changedValue }) - await getList() - } catch { - row.visible = !changedValue - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/product/property/PropertyForm.vue b/src/views/mall/product/property/PropertyForm.vue deleted file mode 100644 index db90beb..0000000 --- a/src/views/mall/product/property/PropertyForm.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ唴瀹�" type="textarea" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as PropertyApi from '@/api/mall/product/property' - -defineOptions({ name: 'ProductPropertyForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '' -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await PropertyApi.getProperty(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as PropertyApi.PropertyVO - if (formType.value === 'create') { - await PropertyApi.createProperty(data) - message.success(t('common.createSuccess')) - } else { - await PropertyApi.updateProperty(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/property/index.vue b/src/views/mall/product/property/index.vue deleted file mode 100644 index ac3401a..0000000 --- a/src/views/mall/product/property/index.vue +++ /dev/null @@ -1,177 +0,0 @@ -<template> - <doc-alert title="銆愬晢鍝併�戝晢鍝佸睘鎬�" url="https://doc.iocoder.cn/mall/product-property/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['product:property:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="缂栧彿" min-width="60" prop="id" /> - <el-table-column align="center" label="灞炴�у悕绉�" prop="name" min-width="150" /> - <el-table-column :show-overflow-tooltip="true" align="center" label="澶囨敞" prop="remark" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['product:property:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button link type="primary" @click="goValueList(scope.row.id)">灞炴�у��</el-button> - <el-button - v-hasPermi="['product:property:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <PropertyForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as PropertyApi from '@/api/mall/product/property' -import PropertyForm from './PropertyForm.vue' - -const { push } = useRouter() - -defineOptions({ name: 'ProductProperty' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PropertyApi.getPropertyPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await PropertyApi.deleteProperty(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 璺宠浆鍟嗗搧灞炴�у垪琛� */ -const goValueList = (id: number) => { - push({ name: 'ProductPropertyValue', params: { propertyId: id } }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/product/property/value/ValueForm.vue b/src/views/mall/product/property/value/ValueForm.vue deleted file mode 100644 index 9e72c09..0000000 --- a/src/views/mall/product/property/value/ValueForm.vue +++ /dev/null @@ -1,105 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - > - <el-form-item label="灞炴�х紪鍙�" prop="category"> - <el-input v-model="formData.propertyId" disabled="" /> - </el-form-item> - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ唴瀹�" type="textarea" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as PropertyApi from '@/api/mall/product/property' - -defineOptions({ name: 'ProductPropertyValueForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - propertyId: undefined, - name: '', - remark: '' -}) -const formRules = reactive({ - propertyId: [{ required: true, message: '灞炴�т笉鑳戒负绌�', trigger: 'blur' }], - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, propertyId: number, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - formData.value.propertyId = propertyId - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await PropertyApi.getPropertyValue(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as PropertyApi.PropertyValueVO - if (formType.value === 'create') { - await PropertyApi.createPropertyValue(data) - message.success(t('common.createSuccess')) - } else { - await PropertyApi.updatePropertyValue(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - propertyId: undefined, - name: '', - remark: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/property/value/index.vue b/src/views/mall/product/property/value/index.vue deleted file mode 100644 index d708172..0000000 --- a/src/views/mall/product/property/value/index.vue +++ /dev/null @@ -1,163 +0,0 @@ -<template> - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="灞炴�ч」" prop="propertyId"> - <el-select v-model="queryParams.propertyId" class="!w-240px" disabled> - <el-option - v-for="item in propertyOptions" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - plain - type="primary" - @click="openForm('create')" - v-hasPermi="['product:property:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" min-width="60" prop="id" /> - <el-table-column label="灞炴�у�煎悕绉�" align="center" min-width="150" prop="name" /> - <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['product:property:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['product:property:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ValueForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as PropertyApi from '@/api/mall/product/property' -import ValueForm from './ValueForm.vue' - -defineOptions({ name: 'ProductPropertyValue' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const { params } = useRoute() // 鏌ヨ鍙傛暟 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - propertyId: Number(params.propertyId), - name: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const propertyOptions = ref([]) // 灞炴�ч」鐨勫垪琛� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PropertyApi.getPropertyValuePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, queryParams.propertyId, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await PropertyApi.deletePropertyValue(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 灞炴�ч」涓嬫媺妗嗘暟鎹� - propertyOptions.value.push(await PropertyApi.getProperty(queryParams.propertyId)) -}) -</script> diff --git a/src/views/mall/product/spu/components/SkuList.vue b/src/views/mall/product/spu/components/SkuList.vue deleted file mode 100644 index 9bbd38e..0000000 --- a/src/views/mall/product/spu/components/SkuList.vue +++ /dev/null @@ -1,576 +0,0 @@ -<template> - <!-- 鎯呭喌涓�锛氭坊鍔�/淇敼 --> - <el-table - v-if="!isDetail && !isActivityComponent" - :data="isBatch ? skuList : formData!.skus!" - border - class="tabNumWidth" - max-height="500" - size="small" - > - <el-table-column align="center" label="鍥剧墖" min-width="65"> - <template #default="{ row }"> - <UploadImg v-model="row.picUrl" height="50px" width="50px" /> - </template> - </el-table-column> - <template v-if="formData!.specType && !isBatch"> - <!-- 鏍规嵁鍟嗗搧灞炴�у姩鎬佹坊鍔� --> - <el-table-column - v-for="(item, index) in tableHeaders" - :key="index" - :label="item.label" - align="center" - min-width="120" - > - <template #default="{ row }"> - <span style="font-weight: bold; color: #40aaff"> - {{ row.properties[index]?.valueName }} - </span> - </template> - </el-table-column> - </template> - <el-table-column align="center" label="鍟嗗搧鏉$爜" min-width="168"> - <template #default="{ row }"> - <el-input v-model="row.barCode" class="w-100%" /> - </template> - </el-table-column> - <el-table-column align="center" label="閿�鍞环" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.price" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <el-table-column align="center" label="甯傚満浠�" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.marketPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <el-table-column align="center" label="鎴愭湰浠�" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.costPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <el-table-column align="center" label="搴撳瓨" min-width="168"> - <template #default="{ row }"> - <el-input-number v-model="row.stock" :min="0" class="w-100%" controls-position="right" /> - </template> - </el-table-column> - <el-table-column align="center" label="閲嶉噺(kg)" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.weight" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <el-table-column align="center" label="浣撶Н(m^3)" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.volume" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <template v-if="formData!.subCommissionType"> - <el-table-column align="center" label="涓�绾ц繑浣�(鍏�)" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.firstBrokeragePrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - <el-table-column align="center" label="浜岀骇杩斾剑(鍏�)" min-width="168"> - <template #default="{ row }"> - <el-input-number - v-model="row.secondBrokeragePrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - controls-position="right" - /> - </template> - </el-table-column> - </template> - <el-table-column v-if="formData?.specType" align="center" fixed="right" label="鎿嶄綔" width="80"> - <template #default="{ row }"> - <el-button v-if="isBatch" link size="small" type="primary" @click="batchAdd"> - 鎵归噺娣诲姞 - </el-button> - <el-button v-else link size="small" type="primary" @click="deleteSku(row)">鍒犻櫎</el-button> - </template> - </el-table-column> - </el-table> - - <!-- 鎯呭喌浜岋細璇︽儏 --> - <el-table - v-if="isDetail" - ref="activitySkuListRef" - :data="formData!.skus!" - border - max-height="500" - size="small" - style="width: 99%" - @selection-change="handleSelectionChange" - > - <el-table-column v-if="isComponent" type="selection" width="45" /> - <el-table-column align="center" label="鍥剧墖" min-width="80"> - <template #default="{ row }"> - <el-image - v-if="row.picUrl" - :src="row.picUrl" - class="h-50px w-50px" - @click="imagePreview(row.picUrl)" - /> - </template> - </el-table-column> - <template v-if="formData!.specType && !isBatch"> - <!-- 鏍规嵁鍟嗗搧灞炴�у姩鎬佹坊鍔� --> - <el-table-column - v-for="(item, index) in tableHeaders" - :key="index" - :label="item.label" - align="center" - min-width="80" - > - <template #default="{ row }"> - <span style="font-weight: bold; color: #40aaff"> - {{ row.properties[index]?.valueName }} - </span> - </template> - </el-table-column> - </template> - <el-table-column align="center" label="鍟嗗搧鏉$爜" min-width="100"> - <template #default="{ row }"> - {{ row.barCode }} - </template> - </el-table-column> - <el-table-column align="center" label="閿�鍞环(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.price }} - </template> - </el-table-column> - <el-table-column align="center" label="甯傚満浠�(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.marketPrice }} - </template> - </el-table-column> - <el-table-column align="center" label="鎴愭湰浠�(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.costPrice }} - </template> - </el-table-column> - <el-table-column align="center" label="搴撳瓨" min-width="80"> - <template #default="{ row }"> - {{ row.stock }} - </template> - </el-table-column> - <el-table-column align="center" label="閲嶉噺(kg)" min-width="80"> - <template #default="{ row }"> - {{ row.weight }} - </template> - </el-table-column> - <el-table-column align="center" label="浣撶Н(m^3)" min-width="80"> - <template #default="{ row }"> - {{ row.volume }} - </template> - </el-table-column> - <template v-if="formData!.subCommissionType"> - <el-table-column align="center" label="涓�绾ц繑浣�(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.firstBrokeragePrice }} - </template> - </el-table-column> - <el-table-column align="center" label="浜岀骇杩斾剑(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.secondBrokeragePrice }} - </template> - </el-table-column> - </template> - </el-table> - - <!-- 鎯呭喌涓夛細浣滀负娲诲姩缁勪欢 --> - <el-table - v-if="isActivityComponent" - :data="formData!.skus!" - border - max-height="500" - size="small" - style="width: 99%" - > - <el-table-column v-if="isComponent" type="selection" width="45" /> - <el-table-column align="center" label="鍥剧墖" min-width="80"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-60px w-60px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <template v-if="formData!.specType"> - <!-- 鏍规嵁鍟嗗搧灞炴�у姩鎬佹坊鍔� --> - <el-table-column - v-for="(item, index) in tableHeaders" - :key="index" - :label="item.label" - align="center" - min-width="80" - > - <template #default="{ row }"> - <span style="font-weight: bold; color: #40aaff"> - {{ row.properties[index]?.valueName }} - </span> - </template> - </el-table-column> - </template> - <el-table-column align="center" label="鍟嗗搧鏉$爜" min-width="100"> - <template #default="{ row }"> - {{ row.barCode }} - </template> - </el-table-column> - <el-table-column align="center" label="閿�鍞环(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.price }} - </template> - </el-table-column> - <el-table-column align="center" label="甯傚満浠�(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.marketPrice }} - </template> - </el-table-column> - <el-table-column align="center" label="鎴愭湰浠�(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ row.costPrice }} - </template> - </el-table-column> - <el-table-column align="center" label="搴撳瓨" min-width="80"> - <template #default="{ row }"> - {{ row.stock }} - </template> - </el-table-column> - <!-- 鏂逛究鎵╁睍姣忎釜娲诲姩閰嶇疆鐨勫睘鎬т笉涓�鏍� --> - <slot name="extension"></slot> - </el-table> -</template> -<script lang="ts" setup> -import { PropType, Ref } from 'vue' -import { copyValueToTarget } from '@/utils' -import { propTypes } from '@/utils/propTypes' -import { UploadImg } from '@/components/UploadFile' -import type { Property, Sku, Spu } from '@/api/mall/product/spu' -import { createImageViewer } from '@/components/ImageViewer' -import { RuleConfig } from '@/views/mall/product/spu/components/index' -import { PropertyAndValues } from './index' -import { ElTable } from 'element-plus' -import { isEmpty } from '@/utils/is' - -defineOptions({ name: 'SkuList' }) -const message = useMessage() // 娑堟伅寮圭獥 - -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - propertyList: { - type: Array as PropType<PropertyAndValues[]>, - default: () => [] - }, - ruleConfig: { - type: Array as PropType<RuleConfig[]>, - default: () => [] - }, - isBatch: propTypes.bool.def(false), // 鏄惁浣滀负鎵归噺鎿嶄綔缁勪欢 - isDetail: propTypes.bool.def(false), // 鏄惁浣滀负 sku 璇︽儏缁勪欢 - isComponent: propTypes.bool.def(false), // 鏄惁浣滀负 sku 閫夋嫨缁勪欢 - isActivityComponent: propTypes.bool.def(false) // 鏄惁浣滀负 sku 娲诲姩閰嶇疆缁勪欢 -}) -const formData: Ref<Spu | undefined> = ref<Spu>() // 琛ㄥ崟鏁版嵁 -const skuList = ref<Sku[]>([ - { - price: 0, // 鍟嗗搧浠锋牸 - marketPrice: 0, // 甯傚満浠� - costPrice: 0, // 鎴愭湰浠� - barCode: '', // 鍟嗗搧鏉$爜 - picUrl: '', // 鍥剧墖鍦板潃 - stock: 0, // 搴撳瓨 - weight: 0, // 鍟嗗搧閲嶉噺 - volume: 0, // 鍟嗗搧浣撶Н - firstBrokeragePrice: 0, // 涓�绾у垎閿�鐨勪剑閲� - secondBrokeragePrice: 0 // 浜岀骇鍒嗛攢鐨勪剑閲� - } -]) // 鎵归噺娣诲姞鏃剁殑涓存椂鏁版嵁 - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - zIndex: 9999999, - urlList: [imgUrl] - }) -} - -/** 鎵归噺娣诲姞 */ -const batchAdd = () => { - validateProperty() - formData.value!.skus!.forEach((item) => { - copyValueToTarget(item, skuList.value[0]) - }) -} -/** 鏍¢獙鍟嗗搧灞炴�у睘鎬у�� */ -const validateProperty = () => { - // 鏍¢獙鍟嗗搧灞炴�у睘鎬у�兼槸鍚︿负绌猴紝鏈変竴涓负绌洪兘涓嶇粰杩� - const warningInfo = '瀛樺湪灞炴�у睘鎬у�间负绌猴紝璇峰厛妫�鏌ュ畬鍠勫睘鎬у�煎悗閲嶈瘯锛侊紒锛�' - for (const item of props.propertyList) { - if (!item.values || isEmpty(item.values)) { - message.warning(warningInfo) - throw new Error(warningInfo) - } - } -} -/** 鍒犻櫎 sku */ -const deleteSku = (row) => { - const index = formData.value!.skus!.findIndex( - // 鐩存帴鎶婂垪琛ㄨ浆鎴愬瓧绗︿覆姣旇緝 - (sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties) - ) - formData.value!.skus!.splice(index, 1) -} -const tableHeaders = ref<{ prop: string; label: string }[]>([]) // 澶氬睘鎬ц〃澶� -/** - * 淇濆瓨鏃讹紝姣忎釜鍟嗗搧瑙勬牸鐨勮〃鍗曡鏍¢獙涓嬨�備緥濡傝锛岄攢鍞噾棰濇渶浣庢槸 0.01 杩欑銆� - */ -const validateSku = () => { - validateProperty() - let warningInfo = '璇锋鏌ュ晢鍝佸悇琛岀浉鍏冲睘鎬ч厤缃紝' - let validate = true // 榛樿閫氳繃 - for (const sku of formData.value!.skus!) { - // 浣滀负娲诲姩缁勪欢鐨勬牎楠� - for (const rule of props?.ruleConfig) { - const arg = getValue(sku, rule.name) - if (!rule.rule(arg)) { - validate = false // 鍙鏈変竴涓笉閫氳繃鍒欑洿鎺ヤ笉閫氳繃 - warningInfo += rule.message - break - } - } - // 鍙鏈変竴涓笉閫氳繃鍒欑粨鏉熷悗缁殑鏍¢獙 - if (!validate) { - message.warning(warningInfo) - throw new Error(warningInfo) - } - } -} -const getValue = (obj, arg) => { - const keys = arg.split('.') - let value = obj - for (const key of keys) { - if (value && typeof value === 'object' && key in value) { - value = value[key] - } else { - value = undefined - break - } - } - return value -} - -const emit = defineEmits<{ - (e: 'selectionChange', value: Sku[]): void -}>() -/** - * 閫夋嫨鏃惰Е鍙� - * @param Sku 浼犻�掕繃鏉ョ殑閫変腑鐨� sku 鏄竴涓暟缁� - */ -const handleSelectionChange = (val: Sku[]) => { - emit('selectionChange', val) -} - -/** - * 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 skuList - */ -watch( - () => props.propFormData, - (data) => { - if (!data) return - formData.value = data - }, - { - deep: true, - immediate: true - } -) - -/** 鐢熸垚琛ㄦ暟鎹� */ -const generateTableData = (propertyList: any[]) => { - // 鏋勫缓鏁版嵁缁撴瀯 - const propertyValues = propertyList.map((item) => - item.values.map((v: any) => ({ - propertyId: item.id, - propertyName: item.name, - valueId: v.id, - valueName: v.name - })) - ) - const buildSkuList = build(propertyValues) - // 濡傛灉鍥炴樉鐨� sku 灞炴�у拰娣诲姞鐨勫睘鎬т笉涓�鑷村垯閲嶇疆 skus 鍒楄〃 - if (!validateData(propertyList)) { - // 濡傛灉涓嶄竴鑷村垯閲嶇疆琛ㄦ暟鎹紝榛樿娣诲姞鏂扮殑灞炴�ч噸鏂扮敓鎴� sku 鍒楄〃 - formData.value!.skus = [] - } - for (const item of buildSkuList) { - const row = { - properties: Array.isArray(item) ? item : [item], // 濡傛灉鍙湁涓�涓睘鎬х殑璇濊繑鍥炵殑鏄竴涓� property 瀵硅薄 - price: 0, - marketPrice: 0, - costPrice: 0, - barCode: '', - picUrl: '', - stock: 0, - weight: 0, - volume: 0, - firstBrokeragePrice: 0, - secondBrokeragePrice: 0 - } - // 濡傛灉瀛樺湪灞炴�х浉鍚岀殑 sku 鍒欎笉鍋氬鐞� - const index = formData.value!.skus!.findIndex( - (sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties) - ) - if (index !== -1) { - continue - } - formData.value!.skus!.push(row) - } -} - -/** - * 鐢熸垚 skus 鍓嶇疆鏍¢獙 - */ -const validateData = (propertyList: any[]) => { - const skuPropertyIds: number[] = [] - formData.value!.skus!.forEach((sku) => - sku.properties - ?.map((property) => property.propertyId) - ?.forEach((propertyId) => { - if (skuPropertyIds.indexOf(propertyId!) === -1) { - skuPropertyIds.push(propertyId!) - } - }) - ) - const propertyIds = propertyList.map((item) => item.id) - return skuPropertyIds.length === propertyIds.length -} - -/** 鏋勫缓鎵�鏈夋帓鍒楃粍鍚� */ -const build = (propertyValuesList: Property[][]) => { - if (propertyValuesList.length === 0) { - return [] - } else if (propertyValuesList.length === 1) { - return propertyValuesList[0] - } else { - const result: Property[][] = [] - const rest = build(propertyValuesList.slice(1)) - for (let i = 0; i < propertyValuesList[0].length; i++) { - for (let j = 0; j < rest.length; j++) { - // 绗竴娆′笉鏄暟缁勭粨鏋勶紝鍚庨潰鐨勯兘鏄暟缁勭粨鏋� - if (Array.isArray(rest[j])) { - result.push([propertyValuesList[0][i], ...rest[j]]) - } else { - result.push([propertyValuesList[0][i], rest[j]]) - } - } - } - return result - } -} - -/** 鐩戝惉灞炴�у垪琛紝鐢熸垚鐩稿叧鍙傛暟鍜岃〃澶� */ -watch( - () => props.propertyList, - (propertyList: PropertyAndValues[]) => { - // 濡傛灉涓嶆槸澶氳鏍煎垯缁撴潫 - if (!formData.value!.specType) { - return - } - // 濡傛灉褰撳墠缁勪欢浣滀负鎵归噺娣诲姞鏁版嵁浣跨敤锛屽垯閲嶇疆琛ㄦ暟鎹� - if (props.isBatch) { - skuList.value = [ - { - price: 0, - marketPrice: 0, - costPrice: 0, - barCode: '', - picUrl: '', - stock: 0, - weight: 0, - volume: 0, - firstBrokeragePrice: 0, - secondBrokeragePrice: 0 - } - ] - } - - // 鍒ゆ柇浠g悊瀵硅薄鏄惁涓虹┖ - if (JSON.stringify(propertyList) === '[]') { - return - } - // 閲嶇疆琛ㄥご - tableHeaders.value = [] - // 鐢熸垚琛ㄥご - propertyList.forEach((item, index) => { - // name鍔犲睘鎬ч」index鍖哄垎灞炴�у�� - tableHeaders.value.push({ prop: `name${index}`, label: item.name }) - }) - // 濡傛灉鍥炴樉鐨� sku 灞炴�у拰娣诲姞鐨勫睘鎬т竴鑷村垯涓嶅鐞� - if (validateData(propertyList)) { - return - } - // 娣诲姞鏂板睘鎬ф病鏈夊睘鎬у�间篃涓嶅仛澶勭悊 - if (propertyList.some((item) => !item.values || isEmpty(item.values))) { - return - } - // 鐢熸垚 table 鏁版嵁锛屽嵆 sku 鍒楄〃 - generateTableData(propertyList) - }, - { - deep: true, - immediate: true - } -) -const activitySkuListRef = ref<InstanceType<typeof ElTable>>() - -const getSkuTableRef = () => { - return activitySkuListRef.value -} -// 鏆撮湶鍑虹敓鎴� sku 鏂规硶锛岀粰娣诲姞灞炴�ф垚鍔熸椂璋冪敤 -defineExpose({ generateTableData, validateSku, getSkuTableRef }) -</script> diff --git a/src/views/mall/product/spu/components/SkuTableSelect.vue b/src/views/mall/product/spu/components/SkuTableSelect.vue deleted file mode 100644 index 13d6ad1..0000000 --- a/src/views/mall/product/spu/components/SkuTableSelect.vue +++ /dev/null @@ -1,95 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :appendToBody="true" title="閫夋嫨瑙勬牸" width="700"> - <el-table v-loading="loading" :data="list" show-overflow-tooltip> - <el-table-column label="#" width="55"> - <template #default="{ row }"> - <el-radio :label="row.id" v-model="selectedSkuId" @change="handleSelected(row)" - > - </el-radio> - </template> - </el-table-column> - <el-table-column label="鍥剧墖" min-width="80"> - <template #default="{ row }"> - <el-image - :src="row.picUrl" - class="h-30px w-30px" - :preview-src-list="[row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="瑙勬牸" align="center" min-width="80"> - <template #default="{ row }"> - {{ row.properties?.map((p) => p.valueName)?.join(' ') }} - </template> - </el-table-column> - <el-table-column align="center" label="閿�鍞环(鍏�)" min-width="80"> - <template #default="{ row }"> - {{ fenToYuan(row.price) }} - </template> - </el-table-column> - </el-table> - </Dialog> -</template> - -<script lang="ts" setup> -import { ElTable } from 'element-plus' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { propTypes } from '@/utils/propTypes' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'SkuTableSelect' }) - -const props = defineProps({ - spuId: propTypes.number.def(null) -}) - -const message = useMessage() // 娑堟伅寮圭獥 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� - -const selectedSkuId = ref() // 閫変腑鐨勫晢鍝� spuId - -/** 閫変腑鏃惰Е鍙� */ -const handleSelected = (row: ProductSpuApi.Sku) => { - emits('change', row) - // 鍏抽棴寮圭獥 - dialogVisible.value = false - selectedSkuId.value = undefined -} - -// 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 -const emits = defineEmits<{ - (e: 'change', spu: ProductSpuApi.Sku): void -}>() - -/** 鎵撳紑寮圭獥 */ -const open = () => { - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getSpuDetail = async () => { - loading.value = true - try { - const spu = await ProductSpuApi.getSpu(props.spuId) - list.value = spu.skus - } finally { - loading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => {}) -watch( - () => props.spuId, - () => { - if (!props.spuId) { - return - } - getSpuDetail() - } -) -</script> diff --git a/src/views/mall/product/spu/components/SpuShowcase.vue b/src/views/mall/product/spu/components/SpuShowcase.vue deleted file mode 100644 index 8bee400..0000000 --- a/src/views/mall/product/spu/components/SpuShowcase.vue +++ /dev/null @@ -1,142 +0,0 @@ -<template> - <div class="flex flex-wrap items-center gap-8px"> - <div v-for="(spu, index) in productSpus" :key="spu.id" class="select-box spu-pic"> - <el-tooltip :content="spu.name"> - <div class="relative h-full w-full"> - <el-image :src="spu.picUrl" class="h-full w-full" /> - <Icon - v-show="!disabled" - class="del-icon" - icon="ep:circle-close-filled" - @click="handleRemoveSpu(index)" - /> - </div> - </el-tooltip> - </div> - <el-tooltip content="閫夋嫨鍟嗗搧" v-if="canAdd"> - <div class="select-box" @click="openSpuTableSelect"> - <Icon icon="ep:plus" /> - </div> - </el-tooltip> - </div> - <!-- 鍟嗗搧閫夋嫨瀵硅瘽妗嗭紙琛ㄦ牸褰㈠紡锛� --> - <SpuTableSelect ref="spuTableSelectRef" :multiple="limit != 1" @change="handleSpuSelected" /> -</template> -<script lang="ts" setup> -import * as ProductSpuApi from '@/api/mall/product/spu' -import SpuTableSelect from '@/views/mall/product/spu/components/SpuTableSelect.vue' -import { propTypes } from '@/utils/propTypes' -import { oneOfType } from 'vue-types' -import { isArray } from '@/utils/is' - -// 鍟嗗搧姗辩獥锛屼竴鑸敤浜庝笌鍟嗗搧寤虹珛鍏崇郴鏃朵娇鐢� -// 鎻愪緵鍔熻兘锛氬睍绀哄晢鍝佸垪琛ㄣ�佹坊鍔犲晢鍝併�佺Щ闄ゅ晢鍝� -defineOptions({ name: 'SpuShowcase' }) - -const props = defineProps({ - modelValue: oneOfType<number | Array<number>>([Number, Array]).isRequired, - // 闄愬埗鏁伴噺锛氶粯璁や笉闄愬埗 - limit: propTypes.number.def(Number.MAX_VALUE), - disabled: propTypes.bool.def(false) -}) - -// 璁$畻鏄惁鍙互娣诲姞 -const canAdd = computed(() => { - // 鎯呭喌涓�锛氱鐢ㄦ椂涓嶅彲浠ユ坊鍔� - if (props.disabled) return false - // 鎯呭喌浜岋細鏈寚瀹氶檺鍒舵暟閲忔椂锛屽彲浠ユ坊鍔� - if (!props.limit) return true - // 鎯呭喌涓夛細妫�鏌ュ凡娣诲姞鏁伴噺鏄惁灏忎簬闄愬埗鏁伴噺 - return productSpus.value.length < props.limit -}) - -// 鍟嗗搧鍒楄〃 -const productSpus = ref<ProductSpuApi.Spu[]>([]) - -watch( - () => props.modelValue, - async () => { - const ids = isArray(props.modelValue) - ? // 鎯呭喌涓�锛氬閫� - props.modelValue - : // 鎯呭喌浜岋細鍗曢�� - props.modelValue - ? [props.modelValue] - : [] - // 涓嶉渶瑕佽繑鏄� - if (ids.length === 0) { - productSpus.value = [] - return - } - // 鍙湁鍟嗗搧鍙戠敓鍙樺寲涔嬪悗锛屾墠鍘绘煡璇㈠晢鍝� - if (productSpus.value.length === 0 || productSpus.value.some((spu) => !ids.includes(spu.id!))) { - productSpus.value = await ProductSpuApi.getSpuDetailList(ids) - } - }, - { immediate: true } -) - -/** 鍟嗗搧琛ㄦ牸閫夋嫨瀵硅瘽妗� */ -const spuTableSelectRef = ref() -// 鎵撳紑瀵硅瘽妗� -const openSpuTableSelect = () => { - spuTableSelectRef.value.open(productSpus.value) -} - -/** - * 閫夋嫨鍟嗗搧鍚庤Е鍙� - * @param spus 閫変腑鐨勫晢鍝佸垪琛� - */ -const handleSpuSelected = (spus: ProductSpuApi.Spu | ProductSpuApi.Spu[]) => { - productSpus.value = isArray(spus) ? spus : [spus] - emitSpuChange() -} - -/** - * 鍒犻櫎鍟嗗搧 - * @param index 鍟嗗搧绱㈠紩 - */ -const handleRemoveSpu = (index: number) => { - productSpus.value.splice(index, 1) - emitSpuChange() -} -const emit = defineEmits(['update:modelValue', 'change']) -const emitSpuChange = () => { - if (props.limit === 1) { - const spu = productSpus.value.length > 0 ? productSpus.value[0] : null - emit('update:modelValue', spu?.id || 0) - emit('change', spu) - } else { - emit( - 'update:modelValue', - productSpus.value.map((spu) => spu.id) - ) - emit('change', productSpus.value) - } -} -</script> - -<style lang="scss" scoped> -.select-box { - display: flex; - width: 60px; - height: 60px; - border: 1px dashed var(--el-border-color-darker); - border-radius: 8px; - align-items: center; - justify-content: center; -} - -.spu-pic { - position: relative; -} - -.del-icon { - position: absolute; - top: -10px; - right: -10px; - z-index: 1; - width: 20px !important; - height: 20px !important; -} -</style> diff --git a/src/views/mall/product/spu/components/SpuTableSelect.vue b/src/views/mall/product/spu/components/SpuTableSelect.vue deleted file mode 100644 index 8028f74..0000000 --- a/src/views/mall/product/spu/components/SpuTableSelect.vue +++ /dev/null @@ -1,303 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :appendToBody="true" title="閫夋嫨鍟嗗搧" width="70%"> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍟嗗搧鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍟嗗搧鍒嗙被" prop="categoryId"> - <el-tree-select - v-model="queryParams.categoryId" - :data="categoryTreeList" - :props="defaultProps" - check-strictly - class="!w-240px" - node-key="id" - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - <el-table v-loading="loading" :data="list" show-overflow-tooltip> - <!-- 1. 澶氶�夋ā寮忥紙涓嶈兘浣跨敤type="selection"锛孍lement浼氬拷鐣eader鎻掓Ы锛� --> - <el-table-column width="55" v-if="multiple"> - <template #header> - <el-checkbox - v-model="isCheckAll" - :indeterminate="isIndeterminate" - @change="handleCheckAll" - /> - </template> - <template #default="{ row }"> - <el-checkbox - v-model="checkedStatus[row.id]" - @change="(checked: boolean) => handleCheckOne(checked, row, true)" - /> - </template> - </el-table-column> - <!-- 2. 鍗曢�夋ā寮� --> - <el-table-column label="#" width="55" v-else> - <template #default="{ row }"> - <el-radio :label="row.id" v-model="selectedSpuId" @change="handleSingleSelected(row)"> - <!-- 绌烘牸涓嶈兘鐪佺暐锛屾槸涓轰簡璁╁崟閫夋涓嶆樉绀簂abel锛屽鏋滀笉鎸囧畾label涓嶄細鏈夐�変腑鐨勬晥鏋� --> - - </el-radio> - </template> - </el-table-column> - <el-table-column key="id" align="center" label="鍟嗗搧缂栧彿" prop="id" min-width="60" /> - <el-table-column label="鍟嗗搧鍥�" min-width="80"> - <template #default="{ row }"> - <el-image - :src="row.picUrl" - class="h-30px w-30px" - :preview-src-list="[row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍚嶇О" min-width="200" prop="name" /> - <el-table-column label="鍟嗗搧鍒嗙被" min-width="100" prop="categoryId"> - <template #default="{ row }"> - <span>{{ categoryList?.find((c) => c.id === row.categoryId)?.name }}</span> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer v-if="multiple"> - <el-button type="primary" @click="handleEmitChange">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { defaultProps, handleTree } from '@/utils/tree' - -import * as ProductCategoryApi from '@/api/mall/product/category' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { propTypes } from '@/utils/propTypes' -import { CHANGE_EVENT } from 'element-plus' - -type Spu = Required<ProductSpuApi.Spu> - -/** - * 鍟嗗搧琛ㄦ牸閫夋嫨瀵硅瘽妗� - * 1. 鍗曢�夋ā寮忥細 - * 1.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫崟閫夋鏃讹紝缁撴潫閫夋嫨锛屽苟鍏抽棴瀵硅瘽妗� - * 1.2 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵�� - * 2. 澶氶�夋ā寮忥細 - * 2.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫閫夋鏃讹紝璁板綍閫変腑鐨勫晢鍝� - * 2.2 鍒囨崲鍒嗛〉鏃讹紝淇濇寔鍟嗗搧鐨勯�変腑鐨勭姸鎬� - * 2.3 鐐瑰嚮鍙充笅瑙掔殑纭畾鎸夐挳鏃讹紝缁撴潫閫夋嫨锛屽叧闂璇濇 - * 2.4 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵�� - */ -defineOptions({ name: 'SpuTableSelect' }) - -defineProps({ - // 澶氶�夋ā寮� - multiple: propTypes.bool.def(false) -}) - -// 鍒楄〃鐨勬�婚〉鏁� -const total = ref(0) -// 鍒楄〃鐨勬暟鎹� -const list = ref<Spu[]>([]) -// 鍒楄〃鐨勫姞杞戒腑 -const loading = ref(false) -// 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogVisible = ref(false) -// 鏌ヨ鍙傛暟 -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - // 榛樿鑾峰彇涓婃灦鐨勫晢鍝� - tabType: 0, - name: '', - categoryId: null, - createTime: [] -}) - -/** 鎵撳紑寮圭獥 */ -const open = (spuList?: Spu[]) => { - // 閲嶇疆 - checkedSpus.value = [] - checkedStatus.value = {} - isCheckAll.value = false - isIndeterminate.value = false - - // 澶勭悊宸查�変腑 - if (spuList && spuList.length > 0) { - checkedSpus.value = [...spuList] - checkedStatus.value = Object.fromEntries(spuList.map((spu) => [spu.id, true])) - } - - dialogVisible.value = true - resetQuery() -} -// 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -defineExpose({ open }) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductSpuApi.getSpuPage(queryParams.value) - list.value = data.list - total.value = data.total - // checkbox缁戝畾undefined浼氭湁闂锛岄渶瑕佺粰涓�涓猙ool鍊� - list.value.forEach( - (spu) => (checkedStatus.value[spu.id] = checkedStatus.value[spu.id] || false) - ) - // 璁$畻鍏ㄩ�夋鐘舵�� - calculateIsCheckAll() - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryParams.value = { - pageNo: 1, - pageSize: 10, - // 榛樿鑾峰彇涓婃灦鐨勫晢鍝� - tabType: 0, - name: '', - categoryId: null, - createTime: [] - } - getList() -} - -// 鏄惁鍏ㄩ�� -const isCheckAll = ref(false) -// 鍏ㄩ�夋鏄惁澶勪簬涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑 -const isIndeterminate = ref(false) -// 閫変腑鐨勫晢鍝� -const checkedSpus = ref<Spu[]>([]) -// 閫変腑鐘舵�侊細key涓哄晢鍝両D锛寁alue涓烘槸鍚﹂�変腑 -const checkedStatus = ref<Record<string, boolean>>({}) - -// 閫変腑鐨勫晢鍝� spuId -const selectedSpuId = ref() -/** 鍗曢�変腑鏃惰Е鍙� */ -const handleSingleSelected = (spu: Spu) => { - emits(CHANGE_EVENT, spu) - // 鍏抽棴寮圭獥 - dialogVisible.value = false - // 璁颁綇涓婃閫夋嫨鐨処D - selectedSpuId.value = spu.id -} - -/** 澶氶�夊畬鎴� */ -const handleEmitChange = () => { - // 鍏抽棴寮圭獥 - dialogVisible.value = false - emits(CHANGE_EVENT, [...checkedSpus.value]) -} - -/** 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 */ -const emits = defineEmits<{ - change: [spu: Spu | Spu[] | any] -}>() - -/** 鍏ㄩ��/鍏ㄤ笉閫� */ -const handleCheckAll = (checked: boolean) => { - isCheckAll.value = checked - isIndeterminate.value = false - - list.value.forEach((spu) => handleCheckOne(checked, spu, false)) -} - -/** - * 閫変腑涓�琛� - * @param checked 鏄惁閫変腑 - * @param spu 鍟嗗搧 - * @param isCalcCheckAll 鏄惁璁$畻鍏ㄩ�� - */ -const handleCheckOne = (checked: boolean, spu: Spu, isCalcCheckAll: boolean) => { - if (checked) { - checkedSpus.value.push(spu) - checkedStatus.value[spu.id] = true - } else { - const index = findCheckedIndex(spu) - if (index > -1) { - checkedSpus.value.splice(index, 1) - checkedStatus.value[spu.id] = false - isCheckAll.value = false - } - } - - // 璁$畻鍏ㄩ�夋鐘舵�� - if (isCalcCheckAll) { - calculateIsCheckAll() - } -} - -// 鏌ユ壘鍟嗗搧鍦ㄥ凡閫変腑鍟嗗搧鍒楄〃涓殑绱㈠紩 -const findCheckedIndex = (spu: Spu) => checkedSpus.value.findIndex((item) => item.id === spu.id) - -// 璁$畻鍏ㄩ�夋鐘舵�� -const calculateIsCheckAll = () => { - isCheckAll.value = list.value.every((spu) => checkedStatus.value[spu.id]) - // 璁$畻涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑 - isIndeterminate.value = !isCheckAll.value && list.value.some((spu) => checkedStatus.value[spu.id]) -} - -// 鍒嗙被鍒楄〃 -const categoryList = ref() -// 鍒嗙被鏍� -const categoryTreeList = ref() -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱鍒嗙被鏍� - categoryList.value = await ProductCategoryApi.getCategoryList({}) - categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId') -}) -</script> diff --git a/src/views/mall/product/spu/components/index.ts b/src/views/mall/product/spu/components/index.ts deleted file mode 100644 index e2cbe73..0000000 --- a/src/views/mall/product/spu/components/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import SkuList from './SkuList.vue' -import { Spu } from '@/api/mall/product/spu' - -interface PropertyAndValues { - id: number - name: string - values?: PropertyAndValues[] -} - -interface RuleConfig { - // 闇�瑕佹牎楠岀殑瀛楁 - // 渚嬶細name: 'name' 鍒欒〃绀烘牎楠� sku.name 鐨勫�� - // 渚嬶細name: 'productConfig.stock' 鍒欒〃绀烘牎楠� sku.productConfig.name 鐨勫��,姝ゅ productConfig 琛ㄧず鎴戝湪 Sku 涓婃墿灞曠殑灞炴�� - name: string - // 鏍¢獙瑙勬牸涓轰竴涓瘉鎺夊嚱鏁帮紝鍏朵腑 arg 涓洪渶瑕佹牎楠岀殑瀛楁鐨勫�笺�� - // 渚嬶細闇�瑕佹牎楠屼环鏍煎繀椤诲ぇ浜�0.01 - // { - // name:'price', - // rule:(arg: number) => arg > 0.01 - // } - rule: (arg: any) => boolean - // 鏍¢獙涓嶉�氳繃鏃剁殑娑堟伅鎻愮ず - message: string -} - -/** - * 鑾峰緱鍟嗗搧鐨勮鏍煎垪琛� - 鍟嗗搧鐩稿叧鐨勫叕鍏卞嚱鏁� - * - * @param spu - * @return PropertyAndValues 瑙勬牸鍒楄〃 - */ -const getPropertyList = (spu: Spu): PropertyAndValues[] => { - // 鐩存帴鎷胯繑鍥炵殑 skus 灞炴�ч�嗗悜鐢熸垚鍑� propertyList - const properties: PropertyAndValues[] = [] - // 鍙湁鏄瑙勬牸鎵嶅鐞� - if (spu.specType) { - spu.skus?.forEach((sku) => { - sku.properties?.forEach(({ propertyId, propertyName, valueId, valueName }) => { - // 娣诲姞灞炴�� - if (!properties?.some((item) => item.id === propertyId)) { - properties.push({ id: propertyId!, name: propertyName!, values: [] }) - } - // 娣诲姞灞炴�у�� - const index = properties?.findIndex((item) => item.id === propertyId) - if (!properties[index].values?.some((value) => value.id === valueId)) { - properties[index].values?.push({ id: valueId!, name: valueName! }) - } - }) - }) - } - return properties -} - -export { SkuList, PropertyAndValues, RuleConfig, getPropertyList } diff --git a/src/views/mall/product/spu/form/DeliveryForm.vue b/src/views/mall/product/spu/form/DeliveryForm.vue deleted file mode 100644 index 1503122..0000000 --- a/src/views/mall/product/spu/form/DeliveryForm.vue +++ /dev/null @@ -1,96 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 鐗╂祦璁剧疆 --> -<template> - <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" :disabled="isDetail"> - <el-form-item label="閰嶉�佹柟寮�" prop="deliveryTypes"> - <el-checkbox-group v-model="formData.deliveryTypes" class="w-80"> - <el-checkbox - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-checkbox> - </el-checkbox-group> - </el-form-item> - <el-form-item - label="杩愯垂妯℃澘" - prop="deliveryTemplateId" - v-if="formData.deliveryTypes?.includes(DeliveryTypeEnum.EXPRESS.type)" - > - <el-select placeholder="璇烽�夋嫨杩愯垂妯℃澘" v-model="formData.deliveryTemplateId" class="w-80"> - <el-option - v-for="item in deliveryTemplateList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-form> -</template> -<script lang="ts" setup> -import { PropType } from 'vue' -import { copyValueToTarget } from '@/utils' -import { propTypes } from '@/utils/propTypes' -import type { Spu } from '@/api/mall/product/spu' -import * as ExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { DeliveryTypeEnum } from '@/utils/constants' - -defineOptions({ name: 'ProductDeliveryForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) -const formRef = ref() // 琛ㄥ崟 Ref -const formData = reactive<Spu>({ - deliveryTypes: [], // 閰嶉�佹柟寮� - deliveryTemplateId: undefined // 杩愯垂妯$増 -}) -const rules = reactive({ - deliveryTypes: [required], - deliveryTemplateId: [required] -}) - -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */ -watch( - () => props.propFormData, - (data) => { - if (!data) { - return - } - copyValueToTarget(formData, data) - }, - { - immediate: true - } -) - -/** 琛ㄥ崟鏍¢獙 */ -const emit = defineEmits(['update:activeName']) -const validate = async () => { - if (!formRef) return - try { - await unref(formRef)?.validate() - // 鏍¢獙閫氳繃鏇存柊鏁版嵁 - Object.assign(props.propFormData, formData) - } catch (e) { - message.error('銆愮墿娴佽缃�戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅') - emit('update:activeName', 'delivery') - throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠� - } -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -const deliveryTemplateList = ref([]) // 杩愯垂妯$増 -onMounted(async () => { - deliveryTemplateList.value = await ExpressTemplateApi.getSimpleTemplateList() -}) -</script> diff --git a/src/views/mall/product/spu/form/DescriptionForm.vue b/src/views/mall/product/spu/form/DescriptionForm.vue deleted file mode 100644 index 2980aa4..0000000 --- a/src/views/mall/product/spu/form/DescriptionForm.vue +++ /dev/null @@ -1,81 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 鍟嗗搧璇︽儏 --> -<template> - <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" :disabled="isDetail"> - <!--瀵屾枃鏈紪杈戝櫒缁勪欢--> - <el-form-item label="鍟嗗搧璇︽儏" prop="description"> - <Editor v-model:modelValue="formData.description" /> - </el-form-item> - </el-form> -</template> -<script lang="ts" setup> -import type { Spu } from '@/api/mall/product/spu' -import { Editor } from '@/components/Editor' -import { PropType } from 'vue' -import { propTypes } from '@/utils/propTypes' -import { copyValueToTarget } from '@/utils' - -defineOptions({ name: 'ProductDescriptionForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - activeName: propTypes.string.def(''), - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) -const formRef = ref() // 琛ㄥ崟Ref -const formData = ref<Spu>({ - description: '' // 鍟嗗搧璇︽儏 -}) -// 琛ㄥ崟瑙勫垯 -const rules = reactive({ - description: [required] -}) - -/** 瀵屾枃鏈紪杈戝櫒濡傛灉杈撳叆杩囧啀娓呯┖浼氭湁娈嬬暀锛岄渶鍐嶉噸缃竴娆� */ -watch( - () => formData.value.description, - (newValue) => { - if ('<p><br></p>' === newValue) { - formData.value.description = '' - } - }, - { - deep: true, - immediate: true - } -) - -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */ -watch( - () => props.propFormData, - (data) => { - if (!data) return - // fix锛氫笁涓〃鍗曠粍浠剁洃鍚祴鍊煎繀椤讳娇鐢� copyValueToTarget 浣跨敤 formData.value = data 浼氱洃鍚潪甯稿娆� - copyValueToTarget(formData.value, data) - }, - { - // fix: 鍘绘帀娣卞害鐩戝惉鍙湁瀵硅薄寮曠敤鍙戠敓鏀瑰彉鐨勬椂鍊欐墠鎵ц,瑙e喅鏀逛竴鍔ㄥ鐨勯棶棰� - immediate: true - } -) - -/** 琛ㄥ崟鏍¢獙 */ -const emit = defineEmits(['update:activeName']) -const validate = async () => { - if (!formRef) return - try { - await unref(formRef)?.validate() - // 鏍¢獙閫氳繃鏇存柊鏁版嵁 - Object.assign(props.propFormData, formData.value) - } catch (e) { - message.error('銆愬晢鍝佽鎯呫�戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅') - emit('update:activeName', 'description') - throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠� - } -} -defineExpose({ validate }) -</script> diff --git a/src/views/mall/product/spu/form/InfoForm.vue b/src/views/mall/product/spu/form/InfoForm.vue deleted file mode 100644 index 76a0970..0000000 --- a/src/views/mall/product/spu/form/InfoForm.vue +++ /dev/null @@ -1,142 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 鍩虹璁剧疆 --> -<template> - <el-form ref="formRef" :disabled="isDetail" :model="formData" :rules="rules" label-width="120px"> - <el-form-item label="鍟嗗搧鍚嶇О" prop="name"> - <el-input - v-model="formData.name" - :autosize="{ minRows: 2, maxRows: 2 }" - :clearable="true" - :show-word-limit="true" - class="w-80!" - maxlength="64" - placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" - type="textarea" - /> - </el-form-item> - <el-form-item label="鍟嗗搧鍒嗙被" prop="categoryId"> - <el-cascader - v-model="formData.categoryId" - :options="categoryList" - :props="defaultProps" - class="w-80" - clearable - filterable - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - /> - </el-form-item> - <el-form-item label="鍟嗗搧鍝佺墝" prop="brandId"> - <el-select v-model="formData.brandId" class="w-80" placeholder="璇烽�夋嫨鍟嗗搧鍝佺墝"> - <el-option - v-for="item in brandList" - :key="item.id" - :label="item.name" - :value="item.id as number" - /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗗搧鍏抽敭瀛�" prop="keyword"> - <el-input v-model="formData.keyword" class="w-80!" placeholder="璇疯緭鍏ュ晢鍝佸叧閿瓧" /> - </el-form-item> - <el-form-item label="鍟嗗搧绠�浠�" prop="introduction"> - <el-input - v-model="formData.introduction" - :autosize="{ minRows: 2, maxRows: 2 }" - :clearable="true" - :show-word-limit="true" - class="w-80!" - maxlength="128" - placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" - type="textarea" - /> - </el-form-item> - <el-form-item label="鍟嗗搧灏侀潰鍥�" prop="picUrl"> - <UploadImg v-model="formData.picUrl" :disabled="isDetail" height="80px" /> - </el-form-item> - <el-form-item label="鍟嗗搧杞挱鍥�" prop="sliderPicUrls"> - <UploadImgs v-model="formData.sliderPicUrls" :disabled="isDetail" /> - </el-form-item> - </el-form> -</template> -<script lang="ts" setup> -import { PropType } from 'vue' -import { copyValueToTarget } from '@/utils' -import { propTypes } from '@/utils/propTypes' -import { defaultProps, handleTree } from '@/utils/tree' -import type { Spu } from '@/api/mall/product/spu' -import * as ProductCategoryApi from '@/api/mall/product/category' -import { CategoryVO } from '@/api/mall/product/category' -import * as ProductBrandApi from '@/api/mall/product/brand' -import { BrandVO } from '@/api/mall/product/brand' - -defineOptions({ name: 'ProductSpuInfoForm' }) -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) - -const message = useMessage() // 娑堟伅寮圭獥 - -const formRef = ref() // 琛ㄥ崟 Ref -const formData = reactive<Spu>({ - name: '', // 鍟嗗搧鍚嶇О - categoryId: undefined, // 鍟嗗搧鍒嗙被 - keyword: '', // 鍏抽敭瀛� - picUrl: '', // 鍟嗗搧灏侀潰鍥� - sliderPicUrls: [], // 鍟嗗搧杞挱鍥� - introduction: '', // 鍟嗗搧绠�浠� - brandId: undefined // 鍟嗗搧鍝佺墝 -}) -const rules = reactive({ - name: [required], - categoryId: [required], - keyword: [required], - introduction: [required], - picUrl: [required], - sliderPicUrls: [required], - brandId: [required] -}) - -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */ -watch( - () => props.propFormData, - (data) => { - if (!data) { - return - } - copyValueToTarget(formData, data) - }, - { - immediate: true - } -) - -/** 琛ㄥ崟鏍¢獙 */ -const emit = defineEmits(['update:activeName']) -const validate = async () => { - if (!formRef) return - try { - await unref(formRef)?.validate() - // 鏍¢獙閫氳繃鏇存柊鏁版嵁 - Object.assign(props.propFormData, formData) - } catch (e) { - message.error('銆愬熀纭�璁剧疆銆戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅') - emit('update:activeName', 'info') - throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠� - } -} -defineExpose({ validate }) - -/** 鍒濆鍖� */ -const brandList = ref<BrandVO[]>([]) // 鍟嗗搧鍝佺墝鍒楄〃 -const categoryList = ref<CategoryVO[]>([]) // 鍟嗗搧鍒嗙被鏍� -onMounted(async () => { - // 鑾峰緱鍒嗙被鏍� - const data = await ProductCategoryApi.getCategoryList({}) - categoryList.value = handleTree(data, 'id') - // 鑾峰彇鍟嗗搧鍝佺墝鍒楄〃 - brandList.value = await ProductBrandApi.getSimpleBrandList() -}) -</script> diff --git a/src/views/mall/product/spu/form/OtherForm.vue b/src/views/mall/product/spu/form/OtherForm.vue deleted file mode 100644 index e7e6358..0000000 --- a/src/views/mall/product/spu/form/OtherForm.vue +++ /dev/null @@ -1,91 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 鍏跺畠璁剧疆 --> -<template> - <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" :disabled="isDetail"> - <el-form-item label="鍟嗗搧鎺掑簭" prop="sort"> - <el-input-number - v-model="formData.sort" - :min="0" - placeholder="璇疯緭鍏ュ晢鍝佹帓搴�" - class="w-80!" - /> - </el-form-item> - <el-form-item label="璧犻�佺Н鍒�" prop="giveIntegral"> - <el-input-number - v-model="formData.giveIntegral" - :min="0" - placeholder="璇疯緭鍏ヨ禒閫佺Н鍒�" - class="w-80!" - /> - </el-form-item> - <el-form-item label="铏氭嫙閿�閲�" prop="virtualSalesCount"> - <el-input-number - v-model="formData.virtualSalesCount" - :min="0" - placeholder="璇疯緭鍏ヨ櫄鎷熼攢閲�" - class="w-80!" - /> - </el-form-item> - </el-form> -</template> -<script lang="ts" setup> -import type { Spu } from '@/api/mall/product/spu' -import { PropType } from 'vue' -import { propTypes } from '@/utils/propTypes' -import { copyValueToTarget } from '@/utils' - -defineOptions({ name: 'ProductOtherForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) - -const formRef = ref() // 琛ㄥ崟Ref -// 琛ㄥ崟鏁版嵁 -const formData = ref<Spu>({ - sort: 0, // 鍟嗗搧鎺掑簭 - giveIntegral: 0, // 璧犻�佺Н鍒� - virtualSalesCount: 0 // 铏氭嫙閿�閲� -}) -// 琛ㄥ崟瑙勫垯 -const rules = reactive({ - sort: [required], - giveIntegral: [required], - virtualSalesCount: [required] -}) - -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */ -watch( - () => props.propFormData, - (data) => { - if (!data) { - return - } - copyValueToTarget(formData.value, data) - }, - { - immediate: true - } -) - -/** 琛ㄥ崟鏍¢獙 */ -const emit = defineEmits(['update:activeName']) -const validate = async () => { - if (!formRef) return - try { - await unref(formRef)?.validate() - // 鏍¢獙閫氳繃鏇存柊鏁版嵁 - Object.assign(props.propFormData, formData.value) - } catch (e) { - message.error('銆愬叾瀹冭缃�戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅') - emit('update:activeName', 'other') - throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠� - } -} -defineExpose({ validate }) -</script> diff --git a/src/views/mall/product/spu/form/ProductAttributes.vue b/src/views/mall/product/spu/form/ProductAttributes.vue deleted file mode 100644 index ffe7397..0000000 --- a/src/views/mall/product/spu/form/ProductAttributes.vue +++ /dev/null @@ -1,125 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 搴撳瓨浠锋牸 - 灞炴�у垪琛� --> -<template> - <el-col v-for="(item, index) in attributeList" :key="index"> - <div> - <el-text class="mx-1">灞炴�у悕锛�</el-text> - <el-tag :closable="!isDetail" class="mx-1" type="success" @close="handleCloseProperty(index)"> - {{ item.name }} - </el-tag> - </div> - <div> - <el-text class="mx-1">灞炴�у�硷細</el-text> - <el-tag - v-for="(value, valueIndex) in item.values" - :key="value.id" - :closable="!isDetail" - class="mx-1" - @close="handleCloseValue(index, valueIndex)" - > - {{ value.name }} - </el-tag> - <el-input - v-show="inputVisible(index)" - :id="`input${index}`" - :ref="setInputRef" - v-model="inputValue" - class="!w-20" - size="small" - @blur="handleInputConfirm(index, item.id)" - @keyup.enter="handleInputConfirm(index, item.id)" - /> - <el-button - v-show="!inputVisible(index)" - class="button-new-tag ml-1" - size="small" - @click="showInput(index)" - > - + 娣诲姞 - </el-button> - </div> - <el-divider class="my-10px" /> - </el-col> -</template> - -<script lang="ts" setup> -import { ElInput } from 'element-plus' -import * as PropertyApi from '@/api/mall/product/property' -import { PropertyAndValues } from '@/views/mall/product/spu/components' -import { propTypes } from '@/utils/propTypes' - -defineOptions({ name: 'ProductAttributes' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const inputValue = ref('') // 杈撳叆妗嗗�� -const attributeIndex = ref<number | null>(null) // 鑾峰彇鐒︾偣鏃惰褰曞綋鍓嶅睘鎬ч」鐨刬ndex -// 杈撳叆妗嗘樉闅愭帶鍒� -const inputVisible = computed(() => (index: number) => { - if (attributeIndex.value === null) return false - if (attributeIndex.value === index) return true -}) -const inputRef = ref<any[]>([]) //鏍囩杈撳叆妗哛ef -/** 瑙e喅 ref 鍦� v-for 涓殑鑾峰彇闂*/ -const setInputRef = (el: any) => { - if (el === null || typeof el === 'undefined') return - // 濡傛灉涓嶅瓨鍦� id 鐩稿悓鐨勫厓绱犳墠娣诲姞 - if (!inputRef.value.some((item) => item.input?.attributes.id === el.input?.attributes.id)) { - inputRef.value.push(el) - } -} -const attributeList = ref<PropertyAndValues[]>([]) // 鍟嗗搧灞炴�у垪琛� -const props = defineProps({ - propertyList: { - type: Array, - default: () => {} - }, - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) - -watch( - () => props.propertyList, - (data) => { - if (!data) return - attributeList.value = data as any - }, - { - deep: true, - immediate: true - } -) - -/** 鍒犻櫎灞炴�у��*/ -const handleCloseValue = (index: number, valueIndex: number) => { - attributeList.value[index].values?.splice(valueIndex, 1) -} - -/** 鍒犻櫎灞炴��*/ -const handleCloseProperty = (index: number) => { - attributeList.value?.splice(index, 1) - emit('success', attributeList.value) -} - -/** 鏄剧ず杈撳叆妗嗗苟鑾峰彇鐒︾偣 */ -const showInput = async (index) => { - attributeIndex.value = index - inputRef.value[index].focus() -} - -/** 杈撳叆妗嗗け鍘荤劍鐐规垨鐐瑰嚮鍥炶溅鏃惰Е鍙� */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const handleInputConfirm = async (index: number, propertyId: number) => { - if (inputValue.value) { - // 淇濆瓨灞炴�у�� - try { - const id = await PropertyApi.createPropertyValue({ propertyId, name: inputValue.value }) - attributeList.value[index].values.push({ id, name: inputValue.value }) - message.success(t('common.createSuccess')) - emit('success', attributeList.value) - } catch { - message.error('娣诲姞澶辫触锛岃閲嶈瘯') - } - } - attributeIndex.value = null - inputValue.value = '' -} -</script> diff --git a/src/views/mall/product/spu/form/ProductPropertyAddForm.vue b/src/views/mall/product/spu/form/ProductPropertyAddForm.vue deleted file mode 100644 index 15c5a8d..0000000 --- a/src/views/mall/product/spu/form/ProductPropertyAddForm.vue +++ /dev/null @@ -1,97 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 搴撳瓨浠锋牸 - 娣诲姞灞炴�� --> -<template> - <Dialog v-model="dialogVisible" title="娣诲姞鍟嗗搧灞炴��"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - @keydown.enter.prevent="submitForm" - > - <el-form-item label="灞炴�у悕绉�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as PropertyApi from '@/api/mall/product/property' - -defineOptions({ name: 'ProductPropertyForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref({ - name: '' -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const attributeList = ref([]) // 鍟嗗搧灞炴�у垪琛� -const props = defineProps({ - propertyList: { - type: Array, - default: () => {} - } -}) - -watch( - () => props.propertyList, // 瑙e喅 props 鏃犳硶鐩存帴淇敼鐖剁粍浠剁殑闂 - (data) => { - if (!data) return - attributeList.value = data - }, - { - deep: true, - immediate: true - } -) - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - resetForm() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as PropertyApi.PropertyVO - const propertyId = await PropertyApi.createProperty(data) - // 娣诲姞鍒板睘鎬у垪琛� - attributeList.value.push({ - id: propertyId, - ...formData.value, - values: [] - }) - message.success(t('common.createSuccess')) - dialogVisible.value = false - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - name: '' - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/product/spu/form/SkuForm.vue b/src/views/mall/product/spu/form/SkuForm.vue deleted file mode 100644 index 9cc6192..0000000 --- a/src/views/mall/product/spu/form/SkuForm.vue +++ /dev/null @@ -1,187 +0,0 @@ -<!-- 鍟嗗搧鍙戝竷 - 搴撳瓨浠锋牸 --> -<template> - <el-form ref="formRef" :disabled="isDetail" :model="formData" :rules="rules" label-width="120px"> - <el-form-item label="鍒嗛攢绫诲瀷" props="subCommissionType"> - <el-radio-group - v-model="formData.subCommissionType" - class="w-80" - @change="changeSubCommissionType" - > - <el-radio :label="false">榛樿璁剧疆</el-radio> - <el-radio :label="true" class="radio">鍗曠嫭璁剧疆</el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鍟嗗搧瑙勬牸" props="specType"> - <el-radio-group v-model="formData.specType" class="w-80" @change="onChangeSpec"> - <el-radio :label="false" class="radio">鍗曡鏍�</el-radio> - <el-radio :label="true">澶氳鏍�</el-radio> - </el-radio-group> - </el-form-item> - <!-- 澶氳鏍兼坊鍔�--> - <el-form-item v-if="!formData.specType"> - <SkuList - ref="skuListRef" - :prop-form-data="formData" - :property-list="propertyList" - :rule-config="ruleConfig" - /> - </el-form-item> - <el-form-item v-if="formData.specType" label="鍟嗗搧灞炴��"> - <el-button class="mb-10px mr-15px" @click="attributesAddFormRef.open">娣诲姞灞炴��</el-button> - <ProductAttributes - :is-detail="isDetail" - :property-list="propertyList" - @success="generateSkus" - /> - </el-form-item> - <template v-if="formData.specType && propertyList.length > 0"> - <el-form-item v-if="!isDetail" label="鎵归噺璁剧疆"> - <SkuList :is-batch="true" :prop-form-data="formData" :property-list="propertyList" /> - </el-form-item> - <el-form-item label="瑙勬牸鍒楄〃"> - <SkuList - ref="skuListRef" - :is-detail="isDetail" - :prop-form-data="formData" - :property-list="propertyList" - :rule-config="ruleConfig" - /> - </el-form-item> - </template> - </el-form> - - <!-- 鍟嗗搧灞炴�ф坊鍔� Form 琛ㄥ崟 --> - <ProductPropertyAddForm ref="attributesAddFormRef" :propertyList="propertyList" /> -</template> -<script lang="ts" setup> -import { PropType } from 'vue' -import { copyValueToTarget } from '@/utils' -import { propTypes } from '@/utils/propTypes' -import { - getPropertyList, - PropertyAndValues, - RuleConfig, - SkuList -} from '@/views/mall/product/spu/components/index' -import ProductAttributes from './ProductAttributes.vue' -import ProductPropertyAddForm from './ProductPropertyAddForm.vue' -import type { Spu } from '@/api/mall/product/spu' - -defineOptions({ name: 'ProductSpuSkuForm' }) - -// sku 鐩稿叧灞炴�ф牎楠岃鍒� -const ruleConfig: RuleConfig[] = [ - { - name: 'stock', - rule: (arg) => arg >= 0, - message: '鍟嗗搧搴撳瓨蹇呴』澶т簬绛変簬 1 锛侊紒锛�' - }, - { - name: 'price', - rule: (arg) => arg >= 0.01, - message: '鍟嗗搧閿�鍞环鏍煎繀椤诲ぇ浜庣瓑浜� 0.01 鍏冿紒锛侊紒' - }, - { - name: 'marketPrice', - rule: (arg) => arg >= 0.01, - message: '鍟嗗搧甯傚満浠锋牸蹇呴』澶т簬绛変簬 0.01 鍏冿紒锛侊紒' - }, - { - name: 'costPrice', - rule: (arg) => arg >= 0.01, - message: '鍟嗗搧鎴愭湰浠锋牸蹇呴』澶т簬绛変簬 0.00 鍏冿紒锛侊紒' - } -] - -const message = useMessage() // 娑堟伅寮圭獥 - -const props = defineProps({ - propFormData: { - type: Object as PropType<Spu>, - default: () => {} - }, - isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢 -}) -const attributesAddFormRef = ref() // 娣诲姞鍟嗗搧灞炴�ц〃鍗� -const formRef = ref() // 琛ㄥ崟 Ref -const propertyList = ref<PropertyAndValues[]>([]) // 鍟嗗搧灞炴�у垪琛� -const skuListRef = ref() // 鍟嗗搧灞炴�у垪琛� Ref -const formData = reactive<Spu>({ - specType: false, // 鍟嗗搧瑙勬牸 - subCommissionType: false, // 鍒嗛攢绫诲瀷 - skus: [] -}) -const rules = reactive({ - specType: [required], - subCommissionType: [required] -}) - -/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */ -watch( - () => props.propFormData, - (data) => { - if (!data) { - return - } - copyValueToTarget(formData, data) - // 灏� SKU 鐨勫睘鎬э紝鏁寸悊鎴� PropertyAndValues 鏁扮粍 - propertyList.value = getPropertyList(data) - }, - { - immediate: true - } -) - -/** 琛ㄥ崟鏍¢獙 */ -const emit = defineEmits(['update:activeName']) -const validate = async () => { - if (!formRef) return - try { - // 鏍¢獙 sku - skuListRef.value.validateSku() - await unref(formRef).validate() - // 鏍¢獙閫氳繃鏇存柊鏁版嵁 - Object.assign(props.propFormData, formData) - } catch (e) { - message.error('銆愬簱瀛樹环鏍笺�戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅') - emit('update:activeName', 'sku') - throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠� - } -} -defineExpose({ validate }) - -/** 鍒嗛攢绫诲瀷 */ -const changeSubCommissionType = () => { - // 榛樿涓洪浂锛岀被鍨嬪垏鎹㈠悗涔熻閲嶇疆涓洪浂 - for (const item of formData.skus!) { - item.firstBrokeragePrice = 0 - item.secondBrokeragePrice = 0 - } -} - -/** 閫夋嫨瑙勬牸 */ -const onChangeSpec = () => { - // 閲嶇疆鍟嗗搧灞炴�у垪琛� - propertyList.value = [] - // 閲嶇疆sku鍒楄〃 - formData.skus = [ - { - price: 0, - marketPrice: 0, - costPrice: 0, - barCode: '', - picUrl: '', - stock: 0, - weight: 0, - volume: 0, - firstBrokeragePrice: 0, - secondBrokeragePrice: 0 - } - ] -} - -/** 璋冪敤 SkuList generateTableData 鏂规硶*/ -const generateSkus = (propertyList: any[]) => { - skuListRef.value.generateTableData(propertyList) -} -</script> diff --git a/src/views/mall/product/spu/form/index.vue b/src/views/mall/product/spu/form/index.vue deleted file mode 100644 index de87452..0000000 --- a/src/views/mall/product/spu/form/index.vue +++ /dev/null @@ -1,204 +0,0 @@ -<template> - <ContentWrap v-loading="formLoading"> - <el-tabs v-model="activeName"> - <el-tab-pane label="鍩虹璁剧疆" name="info"> - <InfoForm - ref="infoRef" - v-model:activeName="activeName" - :is-detail="isDetail" - :propFormData="formData" - /> - </el-tab-pane> - <el-tab-pane label="浠锋牸搴撳瓨" name="sku"> - <SkuForm - ref="skuRef" - v-model:activeName="activeName" - :is-detail="isDetail" - :propFormData="formData" - /> - </el-tab-pane> - <el-tab-pane label="鐗╂祦璁剧疆" name="delivery"> - <DeliveryForm - ref="deliveryRef" - v-model:activeName="activeName" - :is-detail="isDetail" - :propFormData="formData" - /> - </el-tab-pane> - <el-tab-pane label="鍟嗗搧璇︽儏" name="description"> - <DescriptionForm - ref="descriptionRef" - v-model:activeName="activeName" - :is-detail="isDetail" - :propFormData="formData" - /> - </el-tab-pane> - <el-tab-pane label="鍏跺畠璁剧疆" name="other"> - <OtherForm - ref="otherRef" - v-model:activeName="activeName" - :is-detail="isDetail" - :propFormData="formData" - /> - </el-tab-pane> - </el-tabs> - <el-form> - <el-form-item style="float: right"> - <el-button v-if="!isDetail" :loading="formLoading" type="primary" @click="submitForm"> - 淇濆瓨 - </el-button> - <el-button @click="close">杩斿洖</el-button> - </el-form-item> - </el-form> - </ContentWrap> -</template> -<script lang="ts" setup> -import { cloneDeep } from 'lodash-es' -import { useTagsViewStore } from '@/store/modules/tagsView' -import * as ProductSpuApi from '@/api/mall/product/spu' -import InfoForm from './InfoForm.vue' -import DescriptionForm from './DescriptionForm.vue' -import OtherForm from './OtherForm.vue' -import SkuForm from './SkuForm.vue' -import DeliveryForm from './DeliveryForm.vue' -import { convertToInteger, floatToFixed2, formatToFraction } from '@/utils' - -defineOptions({ name: 'ProductSpuForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const { push, currentRoute } = useRouter() // 璺敱 -const { params, name } = useRoute() // 鏌ヨ鍙傛暟 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const activeName = ref('info') // Tag 婵�娲荤殑绐楀彛 -const isDetail = ref(false) // 鏄惁鏌ョ湅璇︽儏 -const infoRef = ref() // 鍟嗗搧淇℃伅 Ref -const skuRef = ref() // 鍟嗗搧瑙勬牸 Ref -const deliveryRef = ref() // 鐗╂祦璁剧疆 Ref -const descriptionRef = ref() // 鍟嗗搧璇︽儏 Ref -const otherRef = ref() // 鍏朵粬璁剧疆 Ref -// SPU 琛ㄥ崟鏁版嵁 -const formData = ref<ProductSpuApi.Spu>({ - name: '', // 鍟嗗搧鍚嶇О - categoryId: undefined, // 鍟嗗搧鍒嗙被 - keyword: '', // 鍏抽敭瀛� - picUrl: '', // 鍟嗗搧灏侀潰鍥� - sliderPicUrls: [], // 鍟嗗搧杞挱鍥� - introduction: '', // 鍟嗗搧绠�浠� - deliveryTypes: [], // 閰嶉�佹柟寮忔暟缁� - deliveryTemplateId: undefined, // 杩愯垂妯$増 - brandId: undefined, // 鍟嗗搧鍝佺墝 - specType: false, // 鍟嗗搧瑙勬牸 - subCommissionType: false, // 鍒嗛攢绫诲瀷 - skus: [ - { - price: 0, // 鍟嗗搧浠锋牸 - marketPrice: 0, // 甯傚満浠� - costPrice: 0, // 鎴愭湰浠� - barCode: '', // 鍟嗗搧鏉$爜 - picUrl: '', // 鍥剧墖鍦板潃 - stock: 0, // 搴撳瓨 - weight: 0, // 鍟嗗搧閲嶉噺 - volume: 0, // 鍟嗗搧浣撶Н - firstBrokeragePrice: 0, // 涓�绾у垎閿�鐨勪剑閲� - secondBrokeragePrice: 0 // 浜岀骇鍒嗛攢鐨勪剑閲� - } - ], - description: '', // 鍟嗗搧璇︽儏 - sort: 0, // 鍟嗗搧鎺掑簭 - giveIntegral: 0, // 璧犻�佺Н鍒� - virtualSalesCount: 0 // 铏氭嫙閿�閲� -}) - -/** 鑾峰緱璇︽儏 */ -const getDetail = async () => { - if ('ProductSpuDetail' === name) { - isDetail.value = true - } - const id = params.id as unknown as number - if (id) { - formLoading.value = true - try { - const res = (await ProductSpuApi.getSpu(id)) as ProductSpuApi.Spu - res.skus?.forEach((item) => { - if (isDetail.value) { - item.price = floatToFixed2(item.price) - item.marketPrice = floatToFixed2(item.marketPrice) - item.costPrice = floatToFixed2(item.costPrice) - item.firstBrokeragePrice = floatToFixed2(item.firstBrokeragePrice) - item.secondBrokeragePrice = floatToFixed2(item.secondBrokeragePrice) - } else { - // 鍥炴樉浠锋牸鍒嗚浆鍏� - item.price = formatToFraction(item.price) - item.marketPrice = formatToFraction(item.marketPrice) - item.costPrice = formatToFraction(item.costPrice) - item.firstBrokeragePrice = formatToFraction(item.firstBrokeragePrice) - item.secondBrokeragePrice = formatToFraction(item.secondBrokeragePrice) - } - }) - formData.value = res - } finally { - formLoading.value = false - } - } -} - -/** 鎻愪氦鎸夐挳 */ -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - // 鏍¢獙鍚勮〃鍗� - await unref(infoRef)?.validate() - await unref(skuRef)?.validate() - await unref(deliveryRef)?.validate() - await unref(descriptionRef)?.validate() - await unref(otherRef)?.validate() - // 娣辨嫹璐濅竴浠�, 杩欐牱鏈�缁� server 绔笉婊¤冻锛屼笉闇�瑕佸奖鍝嶅師濮嬫暟鎹� - const deepCopyFormData = cloneDeep(unref(formData.value)) as ProductSpuApi.Spu - deepCopyFormData.skus!.forEach((item) => { - // 缁檚ku name璧嬪�� - item.name = deepCopyFormData.name - // sku鐩稿叧浠锋牸鍏冭浆鍒� - item.price = convertToInteger(item.price) - item.marketPrice = convertToInteger(item.marketPrice) - item.costPrice = convertToInteger(item.costPrice) - item.firstBrokeragePrice = convertToInteger(item.firstBrokeragePrice) - item.secondBrokeragePrice = convertToInteger(item.secondBrokeragePrice) - }) - // 澶勭悊杞挱鍥惧垪琛� - const newSliderPicUrls: any[] = [] - deepCopyFormData.sliderPicUrls!.forEach((item: any) => { - // 濡傛灉鏄墠绔�夌殑鍥� - typeof item === 'object' ? newSliderPicUrls.push(item.url) : newSliderPicUrls.push(item) - }) - deepCopyFormData.sliderPicUrls = newSliderPicUrls - // 鏍¢獙閮介�氳繃鍚庢彁浜よ〃鍗� - const data = deepCopyFormData as ProductSpuApi.Spu - const id = params.id as unknown as number - if (!id) { - await ProductSpuApi.createSpu(data) - message.success(t('common.createSuccess')) - } else { - await ProductSpuApi.updateSpu(data) - message.success(t('common.updateSuccess')) - } - close() - } finally { - formLoading.value = false - } -} - -/** 鍏抽棴鎸夐挳 */ -const close = () => { - delView(unref(currentRoute)) - push({ name: 'ProductSpu' }) -} - -/** 鍒濆鍖� */ -onMounted(async () => { - await getDetail() -}) -</script> diff --git a/src/views/mall/product/spu/index.vue b/src/views/mall/product/spu/index.vue deleted file mode 100644 index d77d25e..0000000 --- a/src/views/mall/product/spu/index.vue +++ /dev/null @@ -1,451 +0,0 @@ -<!-- 鍟嗗搧涓績 - 鍟嗗搧鍒楄〃 --> -<template> - <doc-alert title="銆愬晢鍝併�戝晢鍝� SPU 涓� SKU" url="https://doc.iocoder.cn/mall/product-spu-sku/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍟嗗搧鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍟嗗搧鍒嗙被" prop="categoryId"> - <el-cascader - v-model="queryParams.categoryId" - :options="categoryList" - :props="defaultProps" - class="w-1/1" - clearable - filterable - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['product:spu:create']" - plain - type="primary" - @click="openForm(undefined)" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - <el-button - v-hasPermi="['product:spu:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-tabs v-model="queryParams.tabType" @tab-click="handleTabClick"> - <el-tab-pane - v-for="item in tabsData" - :key="item.type" - :label="item.name + '(' + item.count + ')'" - :name="item.type" - /> - </el-tabs> - <el-table v-loading="loading" :data="list"> - <el-table-column type="expand"> - <template #default="{ row }"> - <el-form class="spu-table-expand" label-position="left"> - <el-row> - <el-col :span="24"> - <el-row> - <el-col :span="8"> - <el-form-item label="鍟嗗搧鍒嗙被:"> - <span>{{ formatCategoryName(row.categoryId) }}</span> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="甯傚満浠�:"> - <span>{{ fenToYuan(row.marketPrice) }}</span> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="鎴愭湰浠�:"> - <span>{{ fenToYuan(row.costPrice) }}</span> - </el-form-item> - </el-col> - </el-row> - </el-col> - </el-row> - <el-row> - <el-col :span="24"> - <el-row> - <el-col :span="8"> - <el-form-item label="娴忚閲�:"> - <span>{{ row.browseCount }}</span> - </el-form-item> - </el-col> - <el-col :span="8"> - <el-form-item label="铏氭嫙閿�閲�:"> - <span>{{ row.virtualSalesCount }}</span> - </el-form-item> - </el-col> - </el-row> - </el-col> - </el-row> - </el-form> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧缂栧彿" min-width="140" prop="id" /> - <el-table-column label="鍟嗗搧淇℃伅" min-width="300"> - <template #default="{ row }"> - <div class="flex"> - <el-image - fit="cover" - :src="row.picUrl" - class="flex-none w-50px h-50px" - @click="imagePreview(row.picUrl)" - /> - <div class="ml-4 overflow-hidden"> - <el-tooltip effect="dark" :content="row.name" placement="top"> - <div> - {{ row.name }} - </div> - </el-tooltip> - </div> - </div> - </template> - </el-table-column> - <el-table-column align="center" label="浠锋牸" min-width="160" prop="price"> - <template #default="{ row }"> 楼 {{ fenToYuan(row.price) }}</template> - </el-table-column> - <el-table-column align="center" label="閿�閲�" min-width="90" prop="salesCount" /> - <el-table-column align="center" label="搴撳瓨" min-width="90" prop="stock" /> - <el-table-column align="center" label="鎺掑簭" min-width="70" prop="sort" /> - <el-table-column align="center" label="閿�鍞姸鎬�" min-width="80"> - <template #default="{ row }"> - <template v-if="row.status >= 0"> - <el-switch - v-model="row.status" - :active-value="1" - :inactive-value="0" - active-text="涓婃灦" - inactive-text="涓嬫灦" - inline-prompt - @change="handleStatusChange(row)" - /> - </template> - <template v-else> - <el-tag type="info">鍥炴敹绔�</el-tag> - </template> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="200"> - <template #default="{ row }"> - <el-button link type="primary" @click="openDetail(row.id)"> 璇︽儏 </el-button> - <el-button - v-hasPermi="['product:spu:update']" - link - type="primary" - @click="openForm(row.id)" - > - 淇敼 - </el-button> - <template v-if="queryParams.tabType === 4"> - <el-button - v-hasPermi="['product:spu:delete']" - link - type="danger" - @click="handleDelete(row.id)" - > - 鍒犻櫎 - </el-button> - <el-button - v-hasPermi="['product:spu:update']" - link - type="primary" - @click="handleStatus02Change(row, ProductSpuStatusEnum.DISABLE.status)" - > - 鎭㈠ - </el-button> - </template> - <template v-else> - <el-button - v-hasPermi="['product:spu:update']" - link - type="danger" - @click="handleStatus02Change(row, ProductSpuStatusEnum.RECYCLE.status)" - > - 鍥炴敹 - </el-button> - </template> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import { TabsPaneContext } from 'element-plus' -import { createImageViewer } from '@/components/ImageViewer' -import { dateFormatter } from '@/utils/formatTime' -import { defaultProps, handleTree, treeToString } from '@/utils/tree' -import { ProductSpuStatusEnum } from '@/utils/constants' -import { fenToYuan } from '@/utils' -import download from '@/utils/download' -import * as ProductSpuApi from '@/api/mall/product/spu' -import * as ProductCategoryApi from '@/api/mall/product/category' - -defineOptions({ name: 'ProductSpu' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const { push } = useRouter() // 璺敱璺宠浆 - -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<ProductSpuApi.Spu[]>([]) // 鍒楄〃鐨勬暟鎹� -// tabs 鏁版嵁 -const tabsData = ref([ - { - name: '鍑哄敭涓�', - type: 0, - count: 0 - }, - { - name: '浠撳簱涓�', - type: 1, - count: 0 - }, - { - name: '宸插敭缃�', - type: 2, - count: 0 - }, - { - name: '璀︽垝搴撳瓨', - type: 3, - count: 0 - }, - { - name: '鍥炴敹绔�', - type: 4, - count: 0 - } -]) - -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - tabType: 0, - name: '', - categoryId: undefined, - createTime: undefined -}) // 鏌ヨ鍙傛暟 -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗昍ef - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductSpuApi.getSpuPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鍒囨崲 Tab */ -const handleTabClick = (tab: TabsPaneContext) => { - queryParams.value.tabType = tab.paneName as number - getList() -} - -/** 鑾峰緱姣忎釜 Tab 鐨勬暟閲� */ -const getTabsCount = async () => { - const res = await ProductSpuApi.getTabsCount() - for (let objName in res) { - tabsData.value[Number(objName)].count = res[objName] - } -} - -/** 娣诲姞鍒颁粨搴� / 鍥炴敹绔欑殑鐘舵�� */ -const handleStatus02Change = async (row: any, newStatus: number) => { - try { - // 浜屾纭 - const text = newStatus === ProductSpuStatusEnum.RECYCLE.status ? '鍔犲叆鍒板洖鏀剁珯' : '鎭㈠鍒颁粨搴�' - await message.confirm(`纭瑕�"${row.name}"${text}鍚楋紵`) - // 鍙戣捣淇敼 - await ProductSpuApi.updateStatus({ id: row.id, status: newStatus }) - message.success(text + '鎴愬姛') - // 鍒锋柊 tabs 鏁版嵁 - await getTabsCount() - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鏇存柊涓婃灦/涓嬫灦鐘舵�� */ -const handleStatusChange = async (row: any) => { - try { - // 浜屾纭 - const text = row.status ? '涓婃灦' : '涓嬫灦' - await message.confirm(`纭瑕�${text}"${row.name}"鍚楋紵`) - // 鍙戣捣淇敼 - await ProductSpuApi.updateStatus({ id: row.id, status: row.status }) - message.success(text + '鎴愬姛') - // 鍒锋柊 tabs 鏁版嵁 - await getTabsCount() - // 鍒锋柊鍒楄〃 - await getList() - } catch { - // 寮傚父鏃讹紝闇�瑕侀噸缃洖涔嬪墠鐨勫�� - row.status = - row.status === ProductSpuStatusEnum.DISABLE.status - ? ProductSpuStatusEnum.ENABLE.status - : ProductSpuStatusEnum.DISABLE.status - } -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ProductSpuApi.deleteSpu(id) - message.success(t('common.delSuccess')) - // 鍒锋柊tabs鏁版嵁 - await getTabsCount() - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鏂板鎴栦慨鏀� */ -const openForm = (id?: number) => { - // 淇敼 - if (typeof id === 'number') { - push({ name: 'ProductSpuEdit', params: { id } }) - return - } - // 鏂板 - push({ name: 'ProductSpuAdd' }) -} - -/** 鏌ョ湅鍟嗗搧璇︽儏 */ -const openDetail = (id: number) => { - push({ name: 'ProductSpuDetail', params: { id } }) -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await ProductSpuApi.exportSpu(queryParams) - download.excel(data, '鍟嗗搧鍒楄〃.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鑾峰彇鍒嗙被鐨勮妭鐐圭殑瀹屾暣缁撴瀯 */ -const categoryList = ref() // 鍒嗙被鏍� -const formatCategoryName = (categoryId: number) => { - return treeToString(categoryList.value, categoryId) -} - -/** 婵�娲绘椂 */ -onActivated(() => { - getList() -}) - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getTabsCount() - await getList() - // 鑾峰緱鍒嗙被鏍� - const data = await ProductCategoryApi.getCategoryList({}) - categoryList.value = handleTree(data, 'id', 'parentId') -}) -</script> -<style lang="scss" scoped> -.spu-table-expand { - padding-left: 42px; - - :deep(.el-form-item__label) { - width: 82px; - font-weight: bold; - color: #99a9bf; - } -} -</style> diff --git a/src/views/mall/promotion/article/ArticleForm.vue b/src/views/mall/promotion/article/ArticleForm.vue deleted file mode 100644 index 1e44fad..0000000 --- a/src/views/mall/promotion/article/ArticleForm.vue +++ /dev/null @@ -1,225 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="70%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="110px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="鏂囩珷鏍囬" prop="title"> - <el-input v-model="formData.title" placeholder="璇疯緭鍏ユ枃绔犳爣棰�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏂囩珷鍒嗙被" prop="categoryId"> - <el-select v-model="formData.categoryId" placeholder="璇烽�夋嫨"> - <el-option - v-for="item in categoryList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏂囩珷浣滆��" prop="author"> - <el-input v-model="formData.author" placeholder="璇疯緭鍏ユ枃绔犱綔鑰�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏂囩珷绠�浠�" prop="introduction"> - <el-input v-model="formData.introduction" placeholder="璇疯緭鍏ユ枃绔犵畝浠�" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鏂囩珷灏侀潰" prop="picUrl"> - <UploadImg v-model="formData.picUrl" height="80px" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏄惁鐑棬" prop="recommendHot"> - <el-radio-group v-model="formData.recommendHot"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鏄惁杞挱鍥�" prop="recommendBanner"> - <el-radio-group v-model="formData.recommendBanner"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鍟嗗搧鍏宠仈" prop="spuId"> - <el-tag v-if="formData.spuId" class="mr-10px"> - {{ spuList.find((item) => item.id === formData.spuId)?.name }} - </el-tag> - <el-button @click="spuSelectRef?.open()">閫夋嫨鍟嗗搧</el-button> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鏂囩珷鍐呭"> - <Editor v-model="formData.content" height="150px" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SpuSelect ref="spuSelectRef" @confirm="selectSpu" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getBoolDictOptions, getIntDictOptions } from '@/utils/dict' -import * as ArticleApi from '@/api/mall/promotion/article' -import * as ArticleCategoryApi from '@/api/mall/promotion/articleCategory' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { SpuSelect } from '@/views/mall/promotion/components' - -defineOptions({ name: 'PromotionArticleForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - categoryId: undefined, - title: undefined, - author: undefined, - picUrl: undefined, - introduction: undefined, - sort: 0, - status: 0, - spuId: 0, - recommendHot: false, - recommendBanner: false, - content: undefined -}) -const formRules = reactive({ - categoryId: [{ required: true, message: '鍒嗙被id涓嶈兘涓虹┖', trigger: 'blur' }], - title: [{ required: true, message: '鏂囩珷鏍囬涓嶈兘涓虹┖', trigger: 'blur' }], - picUrl: [{ required: true, message: '鏂囩珷灏侀潰鍥剧墖鍦板潃涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - spuId: [{ required: true, message: '鍟嗗搧鍏宠仈id涓嶈兘涓虹┖', trigger: 'blur' }], - recommendHot: [{ required: true, message: '鏄惁鐑棬(灏忕▼搴�)涓嶈兘涓虹┖', trigger: 'blur' }], - recommendBanner: [{ required: true, message: '鏄惁杞挱鍥�(灏忕▼搴�)涓嶈兘涓虹┖', trigger: 'blur' }], - content: [{ required: true, message: '鏂囩珷鍐呭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const spuSelectRef = ref() // 鍟嗗搧鍜屽睘鎬ч�夋嫨 Ref -const selectSpu = (spuId: number) => { - formData.value.spuId = spuId -} -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ArticleApi.getArticle(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ArticleApi.ArticleVO - if (formType.value === 'create') { - await ArticleApi.createArticle(data) - message.success(t('common.createSuccess')) - } else { - await ArticleApi.updateArticle(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - categoryId: undefined, - title: undefined, - author: undefined, - picUrl: undefined, - introduction: undefined, - sort: 0, - status: 0, - spuId: 0, - recommendHot: false, - recommendBanner: false, - content: undefined - } - formRef.value?.resetFields() -} - -const categoryList = ref<ArticleCategoryApi.ArticleCategoryVO[]>([]) -const spuList = ref<ProductSpuApi.Spu[]>([]) -onMounted(async () => { - categoryList.value = - (await ArticleCategoryApi.getSimpleArticleCategoryList()) as ArticleCategoryApi.ArticleCategoryVO[] - spuList.value = (await ProductSpuApi.getSpuSimpleList()) as ProductSpuApi.Spu[] -}) -</script> diff --git a/src/views/mall/promotion/article/category/ArticleCategoryForm.vue b/src/views/mall/promotion/article/category/ArticleCategoryForm.vue deleted file mode 100644 index f8da3bc..0000000 --- a/src/views/mall/promotion/article/category/ArticleCategoryForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戝唴瀹圭鐞�" url="https://doc.iocoder.cn/mall/promotion-content/" /> - - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="鍒嗙被鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ垎绫诲悕绉�" /> - </el-form-item> - <el-form-item label="鍥炬爣鍦板潃" prop="picUrl"> - <UploadImg v-model="formData.picUrl" height="80px" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as ArticleCategoryApi from '@/api/mall/promotion/articleCategory' -import { CommonStatusEnum } from '@/utils/constants' - -defineOptions({ name: 'PromotionArticleCategoryForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - picUrl: undefined, - status: undefined, - sort: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鍒嗙被鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await ArticleCategoryApi.getArticleCategory(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ArticleCategoryApi.ArticleCategoryVO - if (formType.value === 'create') { - await ArticleCategoryApi.createArticleCategory(data) - message.success(t('common.createSuccess')) - } else { - await ArticleCategoryApi.updateArticleCategory(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - picUrl: undefined, - status: CommonStatusEnum.ENABLE, - sort: 0 - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/promotion/article/category/index.vue b/src/views/mall/promotion/article/category/index.vue deleted file mode 100644 index 73d1420..0000000 --- a/src/views/mall/promotion/article/category/index.vue +++ /dev/null @@ -1,199 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍒嗙被鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ垎绫诲悕绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="璇烽�夋嫨鐘舵��"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['promotion:article-category:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="缂栧彿" prop="id" min-width="100" /> - <el-table-column align="center" label="鍒嗙被鍚嶇О" prop="name" min-width="240" /> - <el-table-column label="鍒嗙被鍥惧浘" min-width="80"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column align="center" label="鐘舵��" prop="status" min-width="150"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎺掑簭" prop="sort" min-width="150" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:article-category:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['promotion:article-category:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ArticleCategoryForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as ArticleCategoryApi from '@/api/mall/promotion/articleCategory' -import ArticleCategoryForm from './ArticleCategoryForm.vue' -import { createImageViewer } from '@/components/ImageViewer' - -defineOptions({ name: 'PromotionArticleCategory' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鍒嗙被鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ArticleCategoryApi.getArticleCategoryPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ArticleCategoryApi.deleteArticleCategory(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/article/index.vue b/src/views/mall/promotion/article/index.vue deleted file mode 100644 index 20ad4ce..0000000 --- a/src/views/mall/promotion/article/index.vue +++ /dev/null @@ -1,229 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戝唴瀹圭鐞�" url="https://doc.iocoder.cn/mall/promotion-content/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="80px" - > - <el-form-item label="鏂囩珷鍒嗙被" prop="categoryId"> - <el-select - v-model="queryParams.categoryId" - class="!w-240px" - placeholder="鍏ㄩ儴" - @keyup.enter="handleQuery" - > - <el-option - v-for="item in categoryList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鏂囩珷鏍囬" prop="title"> - <el-input - v-model="queryParams.title" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ枃绔犳爣棰�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="璇烽�夋嫨鐘舵��"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['promotion:article:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="灏侀潰" min-width="80" prop="picUrl"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column align="center" label="鏍囬" min-width="180" prop="title" /> - <el-table-column align="center" label="鍒嗙被" min-width="180" prop="categoryId"> - <template #default="scope"> - {{ categoryList.find((item) => item.id === scope.row.categoryId)?.name }} - </template> - </el-table-column> - <el-table-column align="center" label="娴忚閲�" min-width="180" prop="browseCount" /> - <el-table-column align="center" label="浣滆��" min-width="180" prop="author" /> - <el-table-column align="center" label="鏂囩珷绠�浠�" min-width="250" prop="introduction" /> - <el-table-column align="center" label="鎺掑簭" min-width="60" prop="sort" /> - <el-table-column align="center" label="鐘舵��" min-width="60" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙戝竷鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="120"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:article:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['promotion:article:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ArticleForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as ArticleApi from '@/api/mall/promotion/article' -import ArticleForm from './ArticleForm.vue' -import * as ArticleCategoryApi from '@/api/mall/promotion/articleCategory' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { createImageViewer } from '@/components/ImageViewer' - -defineOptions({ name: 'PromotionArticle' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - categoryId: undefined, - title: null, - status: undefined, - spuId: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -/** 鏂囩珷灏侀潰棰勮 */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ArticleApi.getArticlePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await ArticleApi.deleteArticle(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -const categoryList = ref<ArticleCategoryApi.ArticleCategoryVO[]>([]) -const spuList = ref<ProductSpuApi.Spu[]>([]) -onMounted(async () => { - await getList() - // 鍔犺浇鍒嗙被銆佸晢鍝佸垪琛� - categoryList.value = - (await ArticleCategoryApi.getSimpleArticleCategoryList()) as ArticleCategoryApi.ArticleCategoryVO[] - spuList.value = (await ProductSpuApi.getSpuSimpleList()) as ProductSpuApi.Spu[] -}) -</script> diff --git a/src/views/mall/promotion/banner/BannerForm.vue b/src/views/mall/promotion/banner/BannerForm.vue deleted file mode 100644 index 03bca0f..0000000 --- a/src/views/mall/promotion/banner/BannerForm.vue +++ /dev/null @@ -1,159 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-row> - <el-col :span="24"> - <el-form-item label="鏍囬" prop="title"> - <el-input v-model="formData.title" placeholder="璇疯緭鍏� Banner 鏍囬" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鍥剧墖" prop="picUrl"> - <UploadImg v-model="formData.picUrl" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="璺宠浆鍦板潃" prop="url"> - <el-input v-model="formData.url" placeholder="璇疯緭鍏ヨ烦杞湴鍧�" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" /> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="浣嶇疆" prop="position"> - <el-radio-group v-model="formData.position"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_BANNER_POSITION)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - <el-col :span="24"> - <el-form-item label="鎻忚堪" prop="memo"> - <el-input v-model="formData.memo" placeholder="璇疯緭鍏ユ弿杩�" type="textarea" /> - </el-form-item> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as BannerApi from '@/api/mall/market/banner' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - title: undefined, - picUrl: undefined, - status: 0, - position: 1, - url: undefined, - sort: 0, - memo: undefined -}) -const formRules = reactive({ - title: [{ required: true, message: 'Banner 鏍囬涓嶈兘涓虹┖', trigger: 'blur' }], - picUrl: [{ required: true, message: '鍥剧墖 URL 涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '娲诲姩鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - position: [{ required: true, message: '浣嶇疆涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - url: [{ required: true, message: '璺宠浆鍦板潃涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await BannerApi.getBanner(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as BannerApi.BannerVO - if (formType.value === 'create') { - await BannerApi.createBanner(data) - message.success(t('common.createSuccess')) - } else { - await BannerApi.updateBanner(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - title: undefined, - picUrl: undefined, - status: 0, - position: 1, - url: undefined, - sort: 0, - memo: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/promotion/banner/index.vue b/src/views/mall/promotion/banner/index.vue deleted file mode 100644 index e25431a..0000000 --- a/src/views/mall/promotion/banner/index.vue +++ /dev/null @@ -1,206 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戝唴瀹圭鐞�" url="https://doc.iocoder.cn/mall/promotion-content/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="100px" - > - <el-form-item label="Banner鏍囬" prop="title"> - <el-input - v-model="queryParams.title" - class="!w-240px" - clearable - placeholder="璇疯緭鍏anner鏍囬" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['promotion:banner:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="Banner鏍囬" prop="title" /> - <el-table-column align="center" label="鍥剧墖" min-width="80" prop="picUrl"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column align="center" label="鐘舵��" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹氫綅" prop="position"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_BANNER_POSITION" :value="scope.row.position" /> - </template> - </el-table-column> - <el-table-column align="center" label="璺宠浆鍦板潃" prop="url" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="鎺掑簭" prop="sort" /> - <el-table-column align="center" label="鎻忚堪" prop="memo" /> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:banner:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['promotion:banner:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BannerForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as BannerApi from '@/api/mall/market/banner' -import BannerForm from './BannerForm.vue' -import { createImageViewer } from '@/components/ImageViewer' - -defineOptions({ name: 'Banner' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - title: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏂囩珷灏侀潰棰勮 */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BannerApi.getBannerPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await BannerApi.deleteBanner(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/bargain/activity/BargainActivityForm.vue b/src/views/mall/promotion/bargain/activity/BargainActivityForm.vue deleted file mode 100644 index d8d1463..0000000 --- a/src/views/mall/promotion/bargain/activity/BargainActivityForm.vue +++ /dev/null @@ -1,233 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%"> - <Form - ref="formRef" - v-loading="formLoading" - :is-col="true" - :rules="rules" - :schema="allSchemas.formSchema" - class="mt-10px" - > - <template #spuId> - <el-button @click="spuSelectRef.open()">閫夋嫨鍟嗗搧</el-button> - <SpuAndSkuList - ref="spuAndSkuListRef" - :rule-config="ruleConfig" - :spu-list="spuList" - :spu-property-list-p="spuPropertyList" - > - <el-table-column align="center" label="鐮嶄环璧峰浠锋牸(鍏�)" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number - v-model="sku.productConfig.bargainFirstPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - /> - </template> - </el-table-column> - <el-table-column align="center" label="鐮嶄环搴曚环(鍏�)" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number - v-model="sku.productConfig.bargainMinPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - /> - </template> - </el-table-column> - <el-table-column align="center" label="娲诲姩搴撳瓨" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number v-model="sku.productConfig.stock" class="w-100%" /> - </template> - </el-table-column> - </SpuAndSkuList> - </template> - </Form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SpuSelect ref="spuSelectRef" :isSelectSku="true" :radio="true" @confirm="selectSpu" /> -</template> -<script lang="ts" setup> -import * as BargainActivityApi from '@/api/mall/promotion/bargain/bargainActivity' -import { BargainProductVO } from '@/api/mall/promotion/bargain/bargainActivity' -import { allSchemas, rules } from './bargainActivity.data' -import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/components' -import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { convertToInteger, formatToFraction } from '@/utils' -import { cloneDeep } from 'lodash-es' - -defineOptions({ name: 'PromotionBargainActivityForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formRef = ref() // 琛ㄥ崟 Ref - -// ================= 鍟嗗搧閫夋嫨鐩稿叧 ================= - -const spuSelectRef = ref() // 鍟嗗搧鍜屽睘鎬ч�夋嫨 Ref -const spuAndSkuListRef = ref() // sku 绉掓潃閰嶇疆缁勪欢Ref -const spuList = ref<BargainActivityApi.SpuExtension[]>([]) // 閫夋嫨鐨� spu -const spuPropertyList = ref<SpuProperty<BargainActivityApi.SpuExtension>[]>([]) -const ruleConfig: RuleConfig[] = [ - { - name: 'productConfig.bargainFirstPrice', - rule: (arg) => arg > 0, - message: '鍟嗗搧鐮嶄环璧峰浠锋牸涓嶈兘灏忎簬 0 锛侊紒锛�' - }, - { - name: 'productConfig.bargainMinPrice', - rule: (arg) => arg >= 0, - message: '鍟嗗搧鐮嶄环搴曚环涓嶈兘灏忎簬 0 锛侊紒锛�' - }, - { - name: 'productConfig.stock', - rule: (arg) => arg >= 1, - message: '鍟嗗搧娲诲姩搴撳瓨涓嶈兘灏忎簬 1 锛侊紒锛�' - } -] -const selectSpu = (spuId: number, skuIds: number[]) => { - formRef.value.setValues({ spuId }) - getSpuDetails(spuId, skuIds) -} -/** - * 鑾峰彇 SPU 璇︽儏 - */ -const getSpuDetails = async ( - spuId: number, - skuIds: number[] | undefined, - products?: BargainProductVO[] -) => { - const spuProperties: SpuProperty<BargainActivityApi.SpuExtension>[] = [] - const res = (await ProductSpuApi.getSpuDetailList([spuId])) as BargainActivityApi.SpuExtension[] - if (res.length == 0) { - return - } - spuList.value = [] - // 鍥犱负鍙兘閫夋嫨涓�涓� - const spu = res[0] - const selectSkus = - typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!)) - selectSkus?.forEach((sku) => { - let config: BargainProductVO = { - spuId: spu.id!, - skuId: sku.id!, - bargainFirstPrice: 1, - bargainMinPrice: 1, - stock: 1 - } - if (typeof products !== 'undefined') { - const product = products.find((item) => item.skuId === sku.id) - if (product) { - product.bargainFirstPrice = formatToFraction(product.bargainFirstPrice) - product.bargainMinPrice = formatToFraction(product.bargainMinPrice) - } - config = product || config - } - sku.productConfig = config - }) - spu.skus = selectSkus as BargainActivityApi.SkuExtension[] - spuProperties.push({ - spuId: spu.id!, - spuDetail: spu, - propertyList: getPropertyList(spu) - }) - spuList.value.push(spu) - spuPropertyList.value = spuProperties -} - -// ================= end ================= - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - await resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = (await BargainActivityApi.getBargainActivity( - id - )) as BargainActivityApi.BargainActivityVO - // 鐢ㄦ埛姣忔鐮嶄环閲戦鍒嗚浆鍏�, 鍒嗚浆鍏� - data.randomMinPrice = formatToFraction(data.randomMinPrice) - data.randomMaxPrice = formatToFraction(data.randomMaxPrice) - // 瀵归綈娲诲姩鍟嗗搧澶勭悊缁撴瀯 - await getSpuDetails( - data.spuId!, - [data.skuId], - [ - { - spuId: data.spuId!, - skuId: data.skuId, - bargainFirstPrice: data.bargainFirstPrice, // 鐮嶄环璧峰浠锋牸锛屽崟浣嶅垎 - bargainMinPrice: data.bargainMinPrice, // 鐮嶄环搴曚环 - stock: data.stock // 娲诲姩搴撳瓨 - } - ] - ) - formRef.value.setValues(data) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = async () => { - spuList.value = [] - spuPropertyList.value = [] - await nextTick() - formRef.value.getElFormRef().resetFields() -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.getElFormRef().validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = cloneDeep(formRef.value.formModel) as BargainActivityApi.BargainActivityVO - const products = spuAndSkuListRef.value.getSkuConfigs('productConfig') - products.forEach((item: BargainProductVO) => { - // 鐮嶄环浠锋牸鍏冭浆鍒� - item.bargainFirstPrice = convertToInteger(item.bargainFirstPrice) - item.bargainMinPrice = convertToInteger(item.bargainMinPrice) - }) - // 鐢ㄦ埛姣忔鐮嶄环閲戦鍒嗚浆鍏�, 鍏冭浆鍒� - data.randomMinPrice = convertToInteger(data.randomMinPrice) - data.randomMaxPrice = convertToInteger(data.randomMaxPrice) - const formData = { ...data, ...products[0] } - if (formType.value === 'create') { - await BargainActivityApi.createBargainActivity(formData) - message.success(t('common.createSuccess')) - } else { - await BargainActivityApi.updateBargainActivity(formData) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} -</script> diff --git a/src/views/mall/promotion/bargain/activity/bargainActivity.data.ts b/src/views/mall/promotion/bargain/activity/bargainActivity.data.ts deleted file mode 100644 index 2b124c4..0000000 --- a/src/views/mall/promotion/bargain/activity/bargainActivity.data.ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { CrudSchema } from '@/hooks/web/useCrudSchemas' -import { dateFormatter2 } from '@/utils/formatTime' - -// 琛ㄥ崟鏍¢獙 -export const rules = reactive({ - name: [required], - startTime: [required], - endTime: [required], - helpMaxCount: [required], - bargainCount: [required], - singleLimitCount: [required] -}) - -// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ -const crudSchemas = reactive<CrudSchema[]>([ - { - label: '鐮嶄环娲诲姩鍚嶇О', - field: 'name', - isSearch: true, - isTable: false, - form: { - colProps: { - span: 24 - } - } - }, - { - label: '娲诲姩寮�濮嬫椂闂�', - field: 'startTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩缁撴潫鏃堕棿', - field: 'endTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '鐮嶄环浜烘暟', - field: 'helpMaxCount', - isSearch: false, - form: { - component: 'InputNumber', - labelMessage: '鍙備笌浜烘暟涓嶈兘灏戜簬涓や汉', - value: 2 - } - }, - { - label: '鏈�澶у府鐮嶆鏁�', - field: 'bargainCount', - isSearch: false, - form: { - component: 'InputNumber', - labelMessage: '鍙備笌浜烘暟涓嶈兘灏戜簬涓や汉', - value: 2 - } - }, - { - label: '鎬婚檺璐暟閲�', - field: 'totalLimitCount', - isSearch: false, - form: { - component: 'InputNumber', - labelMessage: '鐢ㄦ埛鏈�澶ц兘鍙戣捣鐮嶄环鐨勬鏁�', - value: 0 - } - }, - { - label: '鐮嶄环鐨勬渶灏忛噾棰�', - field: 'randomMinPrice', - isSearch: false, - isTable: false, - form: { - component: 'InputNumber', - componentProps: { - min: 0, - precision: 2, - step: 0.1 - }, - labelMessage: '鐢ㄦ埛姣忔鐮嶄环鐨勬渶灏忛噾棰�', - value: 0 - } - }, - { - label: '鐮嶄环鐨勬渶澶ч噾棰�', - field: 'randomMaxPrice', - isSearch: false, - isTable: false, - form: { - component: 'InputNumber', - componentProps: { - min: 0, - precision: 2, - step: 0.1 - }, - labelMessage: '鐢ㄦ埛姣忔鐮嶄环鐨勬渶澶ч噾棰�', - value: 0 - } - }, - { - label: '鐮嶄环鍟嗗搧', - field: 'spuId', - isSearch: false, - form: { - colProps: { - span: 24 - } - } - } -]) -export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/src/views/mall/promotion/bargain/activity/index.vue b/src/views/mall/promotion/bargain/activity/index.vue deleted file mode 100644 index 40449fe..0000000 --- a/src/views/mall/promotion/bargain/activity/index.vue +++ /dev/null @@ -1,234 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戠爫浠锋椿鍔�" url="https://doc.iocoder.cn/mall/promotion-bargain/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:bargain-activity:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="娲诲姩缂栧彿" prop="id" min-width="80" /> - <el-table-column label="娲诲姩鍚嶇О" prop="name" min-width="140" /> - <el-table-column label="娲诲姩鏃堕棿" min-width="210"> - <template #default="scope"> - {{ formatDate(scope.row.startTime, 'YYYY-MM-DD') }} - ~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }} - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍥剧墖" prop="spuName" min-width="80"> - <template #default="scope"> - <el-image - :src="scope.row.picUrl" - class="h-40px w-40px" - :preview-src-list="[scope.row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鏍囬" prop="spuName" min-width="300" /> - <el-table-column - label="璧峰浠锋牸" - prop="bargainFirstPrice" - min-width="100" - :formatter="fenToYuanFormat" - /> - <el-table-column - label="鐮嶄环搴曚环" - prop="bargainMinPrice" - min-width="100" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鎬荤爫浠蜂汉鏁�" prop="recordUserCount" min-width="100" /> - <el-table-column label="鎴愬姛鐮嶄环浜烘暟" prop="recordSuccessUserCount" min-width="110" /> - <el-table-column label="鍔╁姏浜烘暟" prop="helpUserCount" min-width="100" /> - <el-table-column label="娲诲姩鐘舵��" align="center" prop="status" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" align="center" prop="stock" min-width="80" /> - <el-table-column label="鎬诲簱瀛�" align="center" prop="totalStock" min-width="80" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:bargain-activity:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleClose(scope.row.id)" - v-if="scope.row.status === 0" - v-hasPermi="['promotion:bargain-activity:close']" - > - 鍏抽棴 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-else - v-hasPermi="['promotion:bargain-activity:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BargainActivityForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as BargainActivityApi from '@/api/mall/promotion/bargain/bargainActivity' -import BargainActivityForm from './BargainActivityForm.vue' -import { formatDate } from '@/utils/formatTime' -import { fenToYuanFormat } from '@/utils/formatter' -import { closeBargainActivity } from '@/api/mall/promotion/bargain/bargainActivity' - -defineOptions({ name: 'PromotionBargainActivity' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BargainActivityApi.getBargainActivityPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -// TODO 鑺嬭壙锛氳繖閲岃鏀逛笅 -/** 鍏抽棴鎸夐挳鎿嶄綔 */ -const handleClose = async (id: number) => { - try { - // 鍏抽棴鐨勪簩娆$‘璁� - await message.confirm('纭鍏抽棴璇ョ爫浠锋椿鍔ㄥ悧锛�') - // 鍙戣捣鍏抽棴 - await BargainActivityApi.closeBargainActivity(id) - message.success('鍏抽棴鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await BargainActivityApi.closeBargainActivity(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> diff --git a/src/views/mall/promotion/bargain/record/BargainRecordListDialog.vue b/src/views/mall/promotion/bargain/record/BargainRecordListDialog.vue deleted file mode 100644 index 9637ac8..0000000 --- a/src/views/mall/promotion/bargain/record/BargainRecordListDialog.vue +++ /dev/null @@ -1,90 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍔╁姏鍒楄〃"> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鐢ㄦ埛缂栧彿" prop="userId" min-width="80px" /> - <el-table-column label="鐢ㄦ埛澶村儚" prop="avatar" min-width="80px"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column label="鐢ㄦ埛鏄电О" prop="nickname" min-width="100px" /> - <el-table-column - label="鐮嶄环閲戦" - prop="reducePrice" - min-width="100px" - :formatter="fenToYuanFormat" - /> - <el-table-column - label="鍔╁姏鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - </Dialog> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as BargainHelpApi from '@/api/mall/promotion/bargain/bargainHelp' -import { fenToYuanFormat } from '@/utils/formatter' - -/** 鍔╁姏鍒楄〃 */ -defineOptions({ name: 'BargainRecordListDialog' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - recordId: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鎵撳紑寮圭獥 */ -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const open = async (recordId: any) => { - dialogVisible.value = true - queryParams.recordId = recordId - resetQuery() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BargainHelpApi.getBargainHelpPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} -</script> diff --git a/src/views/mall/promotion/bargain/record/index.vue b/src/views/mall/promotion/bargain/record/index.vue deleted file mode 100644 index 306d8ea..0000000 --- a/src/views/mall/promotion/bargain/record/index.vue +++ /dev/null @@ -1,197 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戠爫浠锋椿鍔�" url="https://doc.iocoder.cn/mall/promotion-bargain/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐮嶄环鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨鐮嶄环鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_BARGAIN_RECORD_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:bargain-record:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['promotion:bargain-record:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" min-width="50" prop="id" /> - <el-table-column label="鍙戣捣鐢ㄦ埛" min-width="120"> - <template #default="scope"> - <el-image - :src="scope.row.avatar" - class="h-20px w-20px" - :preview-src-list="[scope.row.avatar]" - preview-teleported - /> - {{ scope.row.nickname }} - </template> - </el-table-column> - <el-table-column - label="鍙戣捣鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鐮嶄环娲诲姩" min-width="150" prop="activity.name" /> - <el-table-column - label="鏈�浣庝环" - min-width="100" - prop="activity.bargainMinPrice" - :formatter="fenToYuanFormat" - /> - <el-table-column - label="褰撳墠浠�" - min-width="100" - prop="bargainPrice" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鎬荤爫浠锋鏁�" min-width="100" prop="activity.helpMaxCount" /> - <el-table-column label="鍓╀綑鐮嶄环娆℃暟" min-width="100" prop="helpCount" /> - <el-table-column label="鐮嶄环鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_BARGAIN_RECORD_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="缁撴潫鏃堕棿" - align="center" - prop="endTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="璁㈠崟缂栧彿" align="center" prop="orderId" /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openRecordListDialog(scope.row.id)" - v-hasPermi="['promotion:bargain-help:query']" - > - 鍔╁姏 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥 --> - <BargainRecordListDialog ref="recordListDialogRef" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as BargainRecordApi from '@/api/mall/promotion/bargain/bargainRecord' -import { fenToYuanFormat } from '@/utils/formatter' -import BargainRecordListDialog from './BargainRecordListDialog.vue' - -defineOptions({ name: 'PromotionBargainRecord' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BargainRecordApi.getBargainRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎵撳紑[鍔╁姏]寮圭獥 */ -const recordListDialogRef = ref() -const openRecordListDialog = (id?: number) => { - recordListDialogRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue b/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue deleted file mode 100644 index 5b6e582..0000000 --- a/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue +++ /dev/null @@ -1,187 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%"> - <Form - ref="formRef" - v-loading="formLoading" - :is-col="true" - :rules="rules" - :schema="allSchemas.formSchema" - class="mt-10px" - > - <template #spuId> - <el-button @click="spuSelectRef.open()">閫夋嫨鍟嗗搧</el-button> - <SpuAndSkuList - ref="spuAndSkuListRef" - :rule-config="ruleConfig" - :spu-list="spuList" - :spu-property-list-p="spuPropertyList" - > - <el-table-column align="center" label="鎷煎洟浠锋牸(鍏�)" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number - v-model="sku.productConfig.combinationPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - /> - </template> - </el-table-column> - </SpuAndSkuList> - </template> - </Form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SpuSelect ref="spuSelectRef" :isSelectSku="true" @confirm="selectSpu" /> -</template> -<script lang="ts" setup> -import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity' -import { CombinationProductVO } from '@/api/mall/promotion/combination/combinationActivity' -import { allSchemas, rules } from './combinationActivity.data' -import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/components' -import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { convertToInteger, formatToFraction } from '@/utils' -import { cloneDeep } from 'lodash-es' - -defineOptions({ name: 'PromotionCombinationActivityForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formRef = ref() // 琛ㄥ崟 Ref - -// ================= 鍟嗗搧閫夋嫨鐩稿叧 ================= - -const spuSelectRef = ref() // 鍟嗗搧鍜屽睘鎬ч�夋嫨 Ref -const spuAndSkuListRef = ref() // sku 绉掓潃閰嶇疆缁勪欢Ref -const spuList = ref<CombinationActivityApi.SpuExtension[]>([]) // 閫夋嫨鐨� spu -const spuPropertyList = ref<SpuProperty<CombinationActivityApi.SpuExtension>[]>([]) -const ruleConfig: RuleConfig[] = [ - { - name: 'productConfig.combinationPrice', - rule: (arg) => arg >= 0.01, - message: '鍟嗗搧鎷煎洟浠锋牸涓嶈兘灏忎簬0.01 锛侊紒锛�' - } -] -const selectSpu = (spuId: number, skuIds: number[]) => { - formRef.value.setValues({ spuId }) - getSpuDetails(spuId, skuIds) -} -/** - * 鑾峰彇 SPU 璇︽儏 - */ -const getSpuDetails = async ( - spuId: number, - skuIds: number[] | undefined, - products?: CombinationProductVO[] -) => { - const spuProperties: SpuProperty<CombinationActivityApi.SpuExtension>[] = [] - const res = (await ProductSpuApi.getSpuDetailList([ - spuId - ])) as CombinationActivityApi.SpuExtension[] - if (res.length == 0) { - return - } - spuList.value = [] - // 鍥犱负鍙兘閫夋嫨涓�涓� - const spu = res[0] - const selectSkus = - typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!)) - selectSkus?.forEach((sku) => { - let config: CombinationProductVO = { - spuId: spu.id!, - skuId: sku.id!, - combinationPrice: 0 - } - if (typeof products !== 'undefined') { - const product = products.find((item) => item.skuId === sku.id) - if (product) { - product.combinationPrice = formatToFraction(product.combinationPrice) - } - config = product || config - } - sku.productConfig = config - }) - spu.skus = selectSkus as CombinationActivityApi.SkuExtension[] - spuProperties.push({ - spuId: spu.id!, - spuDetail: spu, - propertyList: getPropertyList(spu) - }) - spuList.value.push(spu) - spuPropertyList.value = spuProperties -} - -// ================= end ================= - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - await resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = (await CombinationActivityApi.getCombinationActivity( - id - )) as CombinationActivityApi.CombinationActivityVO - await getSpuDetails(data.spuId!, data.products?.map((sku) => sku.skuId), data.products) - formRef.value.setValues(data) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = async () => { - spuList.value = [] - spuPropertyList.value = [] - await nextTick() - formRef.value.getElFormRef().resetFields() -} - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.getElFormRef().validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - // 鑾峰緱鎷煎洟鍟嗗搧閰嶇疆 - const products = cloneDeep(spuAndSkuListRef.value.getSkuConfigs('productConfig')) - products.forEach((item: CombinationActivityApi.CombinationProductVO) => { - item.combinationPrice = convertToInteger(item.combinationPrice) - }) - const data = cloneDeep(formRef.value.formModel) as CombinationActivityApi.CombinationActivityVO - data.products = products - // 鐪熸鎻愪氦 - if (formType.value === 'create') { - await CombinationActivityApi.createCombinationActivity(data) - message.success(t('common.createSuccess')) - } else { - await CombinationActivityApi.updateCombinationActivity(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} -</script> diff --git a/src/views/mall/promotion/combination/activity/combinationActivity.data.ts b/src/views/mall/promotion/combination/activity/combinationActivity.data.ts deleted file mode 100644 index dd3e48f..0000000 --- a/src/views/mall/promotion/combination/activity/combinationActivity.data.ts +++ /dev/null @@ -1,140 +0,0 @@ -import type { CrudSchema } from '@/hooks/web/useCrudSchemas' -import { dateFormatter2 } from '@/utils/formatTime' - -// 琛ㄥ崟鏍¢獙 -export const rules = reactive({ - name: [required], - totalLimitCount: [required], - singleLimitCount: [required], - startTime: [required], - endTime: [required], - userSize: [required], - limitDuration: [required], - virtualGroup: [required] -}) - -// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ -const crudSchemas = reactive<CrudSchema[]>([ - { - label: '鎷煎洟鍚嶇О', - field: 'name', - isSearch: true, - isTable: false, - form: { - colProps: { - span: 24 - } - } - }, - { - label: '娲诲姩寮�濮嬫椂闂�', - field: 'startTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩缁撴潫鏃堕棿', - field: 'endTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '鍙備笌浜烘暟', - field: 'userSize', - isSearch: false, - form: { - component: 'InputNumber', - labelMessage: '鍙備笌浜烘暟涓嶈兘灏戜簬涓や汉', - value: 2 - } - }, - { - label: '闄愬埗鏃堕暱', - field: 'limitDuration', - isSearch: false, - isTable: false, - form: { - component: 'InputNumber', - labelMessage: '闄愬埗鏃堕暱(灏忔椂)', - componentProps: { - placeholder: '璇疯緭鍏ラ檺鍒舵椂闀�(灏忔椂)' - } - } - }, - { - label: '鎬婚檺璐暟閲�', - field: 'totalLimitCount', - isSearch: false, - isTable: false, - form: { - component: 'InputNumber', - value: 0 - } - }, - { - label: '鍗曟闄愯喘鏁伴噺', - field: 'singleLimitCount', - isSearch: false, - isTable: false, - form: { - component: 'InputNumber', - value: 0 - } - }, - { - label: '铏氭嫙鎴愬洟', - field: 'virtualGroup', - dictType: DICT_TYPE.INFRA_BOOLEAN_STRING, - dictClass: 'boolean', - isSearch: true, - form: { - component: 'Radio', - value: false - } - }, - { - label: '鎷煎洟鍟嗗搧', - field: 'spuId', - isSearch: false, - form: { - colProps: { - span: 24 - } - } - } -]) -export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/src/views/mall/promotion/combination/activity/index.vue b/src/views/mall/promotion/combination/activity/index.vue deleted file mode 100644 index 02c7de2..0000000 --- a/src/views/mall/promotion/combination/activity/index.vue +++ /dev/null @@ -1,236 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戞嫾鍥㈡椿鍔�" url="https://doc.iocoder.cn/mall/promotion-combination/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:combination-activity:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="娲诲姩缂栧彿" prop="id" min-width="80" /> - <el-table-column label="娲诲姩鍚嶇О" prop="name" min-width="140" /> - <el-table-column label="娲诲姩鏃堕棿" min-width="210"> - <template #default="scope"> - {{ formatDate(scope.row.startTime, 'YYYY-MM-DD') }} - ~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }} - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍥剧墖" prop="spuName" min-width="80"> - <template #default="scope"> - <el-image - :src="scope.row.picUrl" - class="h-40px w-40px" - :preview-src-list="[scope.row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鏍囬" prop="spuName" min-width="300" /> - <el-table-column - label="鍘熶环" - prop="marketPrice" - min-width="100" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鎷煎洟浠�" prop="seckillPrice" min-width="100"> - <template #default="scope"> - {{ formatCombinationPrice(scope.row.products) }} - </template> - </el-table-column> - <el-table-column label="寮�鍥㈢粍鏁�" prop="groupCount" min-width="100" /> - <el-table-column label="鎴愬洟缁勬暟" prop="groupSuccessCount" min-width="100" /> - <el-table-column label="璐拱娆℃暟" prop="recordCount" min-width="100" /> - <el-table-column label="娲诲姩鐘舵��" align="center" prop="status" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:combination-activity:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleClose(scope.row.id)" - v-if="scope.row.status === 0" - v-hasPermi="['promotion:combination-activity:close']" - > - 鍏抽棴 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-else - v-hasPermi="['promotion:combination-activity:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CombinationActivityForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity' -import CombinationActivityForm from './CombinationActivityForm.vue' -import { formatDate } from '@/utils/formatTime' -import { fenToYuanFormat } from '@/utils/formatter' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'PromotionBargainActivity' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CombinationActivityApi.getCombinationActivityPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -// TODO 鑺嬭壙锛氳繖閲岃鏀逛笅 -/** 鍏抽棴鎸夐挳鎿嶄綔 */ -const handleClose = async (id: number) => { - try { - // 鍏抽棴鐨勪簩娆$‘璁� - await message.confirm('纭鍏抽棴璇ョ鏉�娲诲姩鍚楋紵') - // 鍙戣捣鍏抽棴 - await CombinationActivityApi.closeCombinationActivity(id) - message.success('鍏抽棴鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await CombinationActivityApi.deleteCombinationActivity(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -const formatCombinationPrice = (products) => { - const combinationPrice = Math.min(...products.map((item) => item.combinationPrice)) - return `锟�${fenToYuan(combinationPrice)}` -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> diff --git a/src/views/mall/promotion/combination/record/CombinationRecordListDialog.vue b/src/views/mall/promotion/combination/record/CombinationRecordListDialog.vue deleted file mode 100644 index 13e04a1..0000000 --- a/src/views/mall/promotion/combination/record/CombinationRecordListDialog.vue +++ /dev/null @@ -1,89 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鎷煎洟鍒楄〃" width="950"> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="缂栧彿" prop="id" min-width="50" /> - <el-table-column align="center" label="澶村儚" prop="avatar" min-width="80"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column align="center" label="鏄电О" prop="nickname" min-width="100" /> - <el-table-column align="center" label="寮�鍥㈠洟闀�" prop="headId" min-width="100"> - <template #default="{ row }: { row: CombinationRecordApi.CombinationRecordVO }"> - <el-tag> {{ row.headId === 0 ? '鍥㈤暱' : '鍥㈠憳' }} </el-tag> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙傚洟鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="缁撴潫鏃堕棿" - prop="endTime" - width="180" - /> - <el-table-column align="center" label="鎷煎洟鐘舵��" prop="status" min-width="150"> - <template #default="scope"> - <dict-tag - :type="DICT_TYPE.PROMOTION_COMBINATION_RECORD_STATUS" - :value="scope.row.status" - /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - </Dialog> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as CombinationRecordApi from '@/api/mall/promotion/combination/combinationRecord' -import { DICT_TYPE } from '@/utils/dict' - -/** 鍔╁姏鍒楄〃 */ -defineOptions({ name: 'CombinationRecordListDialog' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - headId: undefined -}) - -/** 鎵撳紑寮圭獥 */ -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const open = async (headId: any) => { - dialogVisible.value = true - queryParams.headId = headId - await getList() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CombinationRecordApi.getCombinationRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} -</script> diff --git a/src/views/mall/promotion/combination/record/index.vue b/src/views/mall/promotion/combination/record/index.vue deleted file mode 100644 index 223a723..0000000 --- a/src/views/mall/promotion/combination/record/index.vue +++ /dev/null @@ -1,276 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戞嫾鍥㈡椿鍔�" url="https://doc.iocoder.cn/mall/promotion-combination/" /> - - <!-- 缁熻淇℃伅灞曠ず --> - <el-row :gutter="12"> - <el-col :span="6"> - <ContentWrap class="h-[110px] pb-0!"> - <div class="flex items-center"> - <div - class="h-[50px] w-[50px] flex items-center justify-center" - style="color: rgb(24 144 255); background-color: rgb(24 144 255 / 10%)" - > - <Icon :size="23" icon="fa:user-times" /> - </div> - <div class="ml-[20px]"> - <div class="mb-8px text-14px text-gray-400">鍙備笌浜烘暟(涓�)</div> - <CountTo - :duration="2600" - :end-val="recordSummary.userCount" - :start-val="0" - class="text-20px" - /> - </div> - </div> - </ContentWrap> - </el-col> - <el-col :span="6"> - <ContentWrap class="h-[110px]"> - <div class="flex items-center"> - <div - class="h-[50px] w-[50px] flex items-center justify-center" - style="color: rgb(162 119 255); background-color: rgb(162 119 255 / 10%)" - > - <Icon :size="23" icon="fa:user-plus" /> - </div> - <div class="ml-[20px]"> - <div class="mb-8px text-14px text-gray-400">鎴愬洟鏁伴噺(涓�)</div> - <CountTo - :duration="2600" - :end-val="recordSummary.successCount" - :start-val="0" - class="text-20px" - /> - </div> - </div> - </ContentWrap> - </el-col> - <el-col :span="6"> - <ContentWrap class="h-[110px]"> - <div class="flex items-center"> - <div - class="h-[50px] w-[50px] flex items-center justify-center" - style="color: rgb(162 119 255); background-color: rgb(162 119 255 / 10%)" - > - <Icon :size="23" icon="fa:user-plus" /> - </div> - <div class="ml-[20px]"> - <div class="mb-8px text-14px text-gray-400">铏氭嫙鎴愬洟(涓�)</div> - <CountTo - :duration="2600" - :end-val="recordSummary.virtualGroupCount" - :start-val="0" - class="text-20px" - /> - </div> - </div> - </ContentWrap> - </el-col> - </el-row> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :shortcuts="defaultShortcuts" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="鎷煎洟鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="(dict, index) in getIntDictOptions( - DICT_TYPE.PROMOTION_COMBINATION_RECORD_STATUS - )" - :key="index" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒嗛〉鍒楄〃鏁版嵁灞曠ず --> - <ContentWrap> - <el-table v-loading="loading" :data="pageList"> - <el-table-column align="center" label="缂栧彿" prop="id" min-width="50" /> - <el-table-column align="center" label="澶村儚" prop="avatar" min-width="80"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column align="center" label="鏄电О" prop="nickname" min-width="100" /> - <el-table-column align="center" label="寮�鍥㈠洟闀�" prop="headId" min-width="100"> - <template #default="{ row }: { row: CombinationRecordApi.CombinationRecordVO }"> - {{ - row.headId ? pageList.find((item) => item.id === row.headId)?.nickname : row.nickname - }} - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="寮�鍥㈡椂闂�" - prop="startTime" - width="180" - /> - <el-table-column - align="center" - label="鎷煎洟鍟嗗搧" - prop="type" - show-overflow-tooltip - min-width="300" - > - <template #defaul="{ row }"> - <el-image - :src="row.picUrl" - class="mr-5px h-30px w-30px align-middle" - @click="imagePreview(row.picUrl)" - /> - <span class="align-middle">{{ row.spuName }}</span> - </template> - </el-table-column> - <el-table-column align="center" label="鍑犱汉鍥�" prop="userSize" min-width="100" /> - <el-table-column align="center" label="鍙備笌浜烘暟" prop="userCount" min-width="100" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍙傚洟鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="缁撴潫鏃堕棿" - prop="endTime" - width="180" - /> - <el-table-column align="center" label="鎷煎洟鐘舵��" prop="status" min-width="150"> - <template #default="scope"> - <dict-tag - :type="DICT_TYPE.PROMOTION_COMBINATION_RECORD_STATUS" - :value="scope.row.status" - /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:combination-record:query']" - link - type="primary" - @click="openRecordListDialog(scope.row)" - > - 鏌ョ湅鎷煎洟 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥 --> - <CombinationRecordListDialog ref="combinationRecordListRef" /> -</template> -<script lang="ts" setup> -import CombinationRecordListDialog from './CombinationRecordListDialog.vue' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter, defaultShortcuts } from '@/utils/formatTime' -import { createImageViewer } from '@/components/ImageViewer' -import * as CombinationRecordApi from '@/api/mall/promotion/combination/combinationRecord' - -defineOptions({ name: 'PromotionCombinationRecord' }) - -const queryParams = ref({ - status: undefined, // 鎷煎洟鐘舵�� - createTime: undefined, // 鍒涘缓鏃堕棿 - pageSize: 10, - pageNo: 1 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const combinationRecordListRef = ref() // 鏌ヨ琛ㄥ崟 Ref -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鎬昏褰曟暟 -const pageList = ref<CombinationRecordApi.CombinationRecordVO[]>([]) // 鍒嗛〉鏁版嵁 -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CombinationRecordApi.getCombinationRecordPage(queryParams.value) - pageList.value = data.list as CombinationRecordApi.CombinationRecordVO[] - total.value = data.total - } finally { - loading.value = false - } -} -// 鎷煎洟缁熻鏁版嵁 -const recordSummary = ref({ - successCount: 0, - userCount: 0, - virtualGroupCount: 0 -}) -/** 鑾峰緱鎷煎洟璁板綍缁熻淇℃伅 */ -const getSummary = async () => { - recordSummary.value = await CombinationRecordApi.getCombinationRecordSummary() -} - -/** 鏌ョ湅鎷煎洟璇︽儏 */ -const openRecordListDialog = (row: CombinationRecordApi.CombinationRecordVO) => { - combinationRecordListRef.value?.open(row.headId || row.id) // 澶氳〃杈惧紡鐨勫師鍥狅紝鍥㈤暱鐨� headId 涓虹┖锛屽氨鏄嚜韬殑鎯呭喌 -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getSummary() - await getList() -}) -</script> diff --git a/src/views/mall/promotion/components/SpuAndSkuList.vue b/src/views/mall/promotion/components/SpuAndSkuList.vue deleted file mode 100644 index facc6cf..0000000 --- a/src/views/mall/promotion/components/SpuAndSkuList.vue +++ /dev/null @@ -1,112 +0,0 @@ -<template> - <el-table :data="spuData" :expand-row-keys="expandRowKeys" row-key="id"> - <el-table-column type="expand" width="30"> - <template #default="{ row }"> - <SkuList - ref="skuListRef" - :is-activity-component="true" - :prop-form-data="spuPropertyList.find((item) => item.spuId === row.id)?.spuDetail" - :property-list="spuPropertyList.find((item) => item.spuId === row.id)?.propertyList" - :rule-config="ruleConfig" - > - <template #extension> - <slot></slot> - </template> - </SkuList> - </template> - </el-table-column> - <el-table-column key="id" align="center" label="鍟嗗搧缂栧彿" prop="id" /> - <el-table-column label="鍟嗗搧鍥�" min-width="80"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column :show-overflow-tooltip="true" label="鍟嗗搧鍚嶇О" min-width="300" prop="name" /> - <el-table-column align="center" label="鍟嗗搧鍞环" min-width="90" prop="price"> - <template #default="{ row }"> - {{ formatToFraction(row.price) }} - </template> - </el-table-column> - <el-table-column align="center" label="閿�閲�" min-width="90" prop="salesCount" /> - <el-table-column align="center" label="搴撳瓨" min-width="90" prop="stock" /> - </el-table> -</template> -<script generic="T extends Spu" lang="ts" setup> -import { formatToFraction } from '@/utils' -import { createImageViewer } from '@/components/ImageViewer' -import { Spu } from '@/api/mall/product/spu' -import { RuleConfig, SkuList } from '@/views/mall/product/spu/components' -import { SpuProperty } from '@/views/mall/promotion/components/index' - -defineOptions({ name: 'PromotionSpuAndSkuList' }) - -const props = defineProps<{ - spuList: T[] - ruleConfig: RuleConfig[] - spuPropertyListP: SpuProperty<T>[] -}>() - -const spuData = ref<Spu[]>([]) // spu 璇︽儏鏁版嵁鍒楄〃 -const skuListRef = ref() // 鍟嗗搧灞炴�у垪琛≧ef -const spuPropertyList = ref<SpuProperty<T>[]>([]) // spuId 瀵瑰簲鐨� sku 鐨勫睘鎬у垪琛� -const expandRowKeys = ref<number[]>() // 鎺у埗灞曞紑琛岄渶瑕佽缃� row-key 灞炴�ф墠鑳戒娇鐢紝璇ュ睘鎬т负灞曞紑琛岀殑 keys 鏁扮粍銆� - -/** - * 鑾峰彇鎵�鏈� sku 娲诲姩閰嶇疆 - * - * @param extendedAttribute 鍦� sku 涓婃墿灞曠殑灞炴�э紝渚嬶細绉掓潃娲诲姩 sku 鎵╁睍灞炴�� productConfig 璇峰弬鑰� seckillActivity.ts - */ -const getSkuConfigs = (extendedAttribute: string) => { - skuListRef.value.validateSku() - const seckillProducts = [] - spuPropertyList.value.forEach((item) => { - item.spuDetail.skus.forEach((sku) => { - seckillProducts.push(sku[extendedAttribute]) - }) - }) - return seckillProducts -} -// 鏆撮湶鍑虹粰琛ㄥ崟鎻愪氦鏃朵娇鐢� -defineExpose({ getSkuConfigs }) - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - zIndex: 99999999, - urlList: [imgUrl] - }) -} - -/** - * 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 skuList - */ -watch( - () => props.spuList, - (data) => { - if (!data) return - spuData.value = data as Spu[] - }, - { - deep: true, - immediate: true - } -) -/** - * 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 skuList - */ -watch( - () => props.spuPropertyListP, - (data) => { - if (!data) return - spuPropertyList.value = data as SpuProperty<T>[] - // 瑙e喅濡傛灉涔嬪墠閫夋嫨鐨勬槸鍗曡鏍� spu 鐨勮瘽鍚庨潰閫夋嫨澶氳鏍� sku 澶氳鏍煎睘鎬т俊鎭笉灞曠ず鐨勯棶棰樸�傝В鍐虫柟娉曪細璁� SkuList 缁勪欢閲嶆柊娓叉煋锛堣鎶樺彔浼氬共鎺夊寘鍚殑缁勪欢灞曞紑鏃朵細閲嶆柊鍔犺浇锛� - setTimeout(() => { - expandRowKeys.value = data.map((item) => item.spuId) - }, 200) - }, - { - deep: true, - immediate: true - } -) -</script> diff --git a/src/views/mall/promotion/components/SpuSelect.vue b/src/views/mall/promotion/components/SpuSelect.vue deleted file mode 100644 index fd7dffe..0000000 --- a/src/views/mall/promotion/components/SpuSelect.vue +++ /dev/null @@ -1,317 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :appendToBody="true" :title="dialogTitle" width="70%"> - <ContentWrap> - <el-row :gutter="20" class="mb-10px"> - <el-col :span="6"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ュ晢鍝佸悕绉�" - @keyup.enter="handleQuery" - /> - </el-col> - <el-col :span="6"> - <el-tree-select - v-model="queryParams.categoryId" - :data="categoryList" - :props="defaultProps" - check-strictly - class="w-1/1" - node-key="id" - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - /> - </el-col> - <el-col :span="6"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-col> - <el-col :span="6"> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-col> - </el-row> - <el-table - ref="spuListRef" - v-loading="loading" - :data="list" - :expand-row-keys="expandRowKeys" - row-key="id" - @expand-change="expandChange" - @selection-change="selectSpu" - > - <el-table-column v-if="isSelectSku" type="expand" width="30"> - <template #default> - <SkuList - v-if="isExpand" - ref="skuListRef" - :isComponent="true" - :isDetail="true" - :prop-form-data="spuData" - :property-list="propertyList" - @selection-change="selectSku" - /> - </template> - </el-table-column> - <el-table-column type="selection" width="55" /> - <el-table-column key="id" align="center" label="鍟嗗搧缂栧彿" prop="id" /> - <el-table-column label="鍟嗗搧鍥�" min-width="80"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column - :show-overflow-tooltip="true" - label="鍟嗗搧鍚嶇О" - min-width="300" - prop="name" - /> - <el-table-column align="center" label="鍟嗗搧鍞环" min-width="90" prop="price"> - <template #default="{ row }"> - {{ formatToFraction(row.price) }} - </template> - </el-table-column> - <el-table-column align="center" label="閿�閲�" min-width="90" prop="salesCount" /> - <el-table-column align="center" label="搴撳瓨" min-width="90" prop="stock" /> - <el-table-column align="center" label="鎺掑簭" min-width="70" prop="sort" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button type="primary" @click="confirm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { getPropertyList, PropertyAndValues, SkuList } from '@/views/mall/product/spu/components' -import { ElTable } from 'element-plus' -import { dateFormatter } from '@/utils/formatTime' -import { createImageViewer } from '@/components/ImageViewer' -import { formatToFraction } from '@/utils' -import { defaultProps, handleTree } from '@/utils/tree' - -import * as ProductCategoryApi from '@/api/mall/product/category' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { propTypes } from '@/utils/propTypes' - -defineOptions({ name: 'PromotionSpuSelect' }) - -const props = defineProps({ - // 榛樿涓嶉渶瑕侊紙涓嶉渶瑕佺殑鎯呭喌涓嬪彧杩斿洖 spu锛岄渶瑕佺殑鎯呭喌涓嬭繑鍥� 閫変腑鐨� spu 鍜� sku 鍒楄〃锛� - // 鍏跺畠娲诲姩闇�瑕侀�夋嫨鍟嗗搧鍜屽晢鍝佸睘鎬у鍏ユ缁勪欢鍗冲彲锛岄渶娣诲姞缁勪欢灞炴�� :isSelectSku='true' - isSelectSku: propTypes.bool.def(false), // 鏄惁闇�瑕侀�夋嫨 sku 灞炴�� - radio: propTypes.bool.def(false) // 鏄惁鍗曢�� sku -}) - -const message = useMessage() // 娑堟伅寮圭獥 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - tabType: 0, // 榛樿鑾峰彇涓婃灦鐨勫晢鍝� - name: '', - categoryId: null, - createTime: [] -}) // 鏌ヨ鍙傛暟 -const propertyList = ref<PropertyAndValues[]>([]) // 鍟嗗搧灞炴�у垪琛� -const spuListRef = ref<InstanceType<typeof ElTable>>() -const skuListRef = ref<InstanceType<typeof SkuList>>() // 鍟嗗搧灞炴�ч�夋嫨 Ref -const spuData = ref<ProductSpuApi.Spu>() // 鍟嗗搧璇︽儏 -const isExpand = ref(false) // 鎺у埗 SKU 鍒楄〃鏄剧ず -const expandRowKeys = ref<number[]>() // 鎺у埗灞曞紑琛岄渶瑕佽缃� row-key 灞炴�ф墠鑳戒娇鐢紝璇ュ睘鎬т负灞曞紑琛岀殑 keys 鏁扮粍銆� - -//============ 鍟嗗搧閫夋嫨鐩稿叧 ============ -const selectedSpuId = ref<number>(0) // 閫変腑鐨勫晢鍝� spuId -const selectedSkuIds = ref<number[]>([]) // 閫変腑鐨勫晢鍝� skuIds -const selectSku = (val: ProductSpuApi.Sku[]) => { - const skuTable = skuListRef.value?.getSkuTableRef() - if (selectedSpuId.value === 0) { - message.warning('璇峰厛閫夋嫨鍟嗗搧鍐嶉�夋嫨鐩稿簲鐨勮鏍硷紒锛侊紒') - skuTable?.clearSelection() - return - } - if (val.length === 0) { - selectedSkuIds.value = [] - return - } - if (props.radio) { - // 鍙�夋嫨涓�涓� - selectedSkuIds.value = [val.map((sku) => sku.id!)[0]] - // 濡傛灉澶т簬1涓� - if (val.length > 1) { - // 娓呯┖閫夋嫨 - skuTable?.clearSelection() - // 鍙樻洿涓烘渶鍚庝竴娆¢�夋嫨鐨� - skuTable?.toggleRowSelection(val.pop(), true) - return - } - } else { - selectedSkuIds.value = val.map((sku) => sku.id!) - } -} -const selectSpu = (val: ProductSpuApi.Spu[]) => { - if (val.length === 0) { - selectedSpuId.value = 0 - return - } - // 鍙�夋嫨涓�涓� - selectedSpuId.value = val.map((spu) => spu.id!)[0] - // 鍒囨崲閫夋嫨 spu 濡傛灉鏈夐�夋嫨鐨� sku 鍒欐竻绌�,纭繚閫夋嫨鐨� sku 鏄搴旂殑 spu 涓嬮潰鐨� - if (selectedSkuIds.value.length > 0) { - selectedSkuIds.value = [] - } - // 濡傛灉澶т簬1涓� - if (val.length > 1) { - // 娓呯┖閫夋嫨 - spuListRef.value?.clearSelection() - // 鍙樻洿涓烘渶鍚庝竴娆¢�夋嫨鐨� - spuListRef.value?.toggleRowSelection(val.pop(), true) - return - } - expandChange(val[0], val) -} - -// 璁$畻鍟嗗搧灞炴�� -const expandChange = async (row: ProductSpuApi.Spu, expandedRows?: ProductSpuApi.Spu[]) => { - // 鍒ゆ柇闇�瑕佸睍寮�鐨� spuId === 閫夋嫨鐨� spuId銆傚鏋滈�夋嫨浜� A 灏卞睍寮� A 鐨� skuList銆傚鏋滈�夋嫨浜� A 鎵嬪姩灞曞紑 B 鍒欓樆鏂� - // 鐩殑闃叉璇�� sku - if (selectedSpuId.value !== 0) { - if (row.id !== selectedSpuId.value) { - message.warning('浣犲凡閫夋嫨鍟嗗搧璇峰厛鍙栨秷') - expandRowKeys.value = [selectedSpuId.value] - return - } - // 濡傛灉宸插睍寮� skuList 鍒欓�夋嫨姝ゅ搴旂殑 spu 涓嶉渶瑕侀噸鏂拌幏鍙栨覆鏌� skuList - if (isExpand.value && spuData.value?.id === row.id) { - return - } - } - spuData.value = {} - propertyList.value = [] - isExpand.value = false - if (expandedRows?.length === 0) { - // 濡傛灉灞曞紑涓暟涓� 0 - expandRowKeys.value = [] - return - } - // 鑾峰彇 SPU 璇︽儏 - const res = (await ProductSpuApi.getSpu(row.id as number)) as ProductSpuApi.Spu - propertyList.value = getPropertyList(res) - spuData.value = res - isExpand.value = true - expandRowKeys.value = [row.id!] -} - -// 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 -const emits = defineEmits<{ - (e: 'confirm', spuId: number, skuIds?: number[]): void -}>() -/** - * 纭閫夋嫨杩斿洖閫変腑鐨� spu 鍜� sku (濡傛灉闇�瑕侀�夋嫨sku鐨勮瘽) - */ -const confirm = () => { - if (selectedSpuId.value === 0) { - message.warning('娌℃湁閫夋嫨浠讳綍鍟嗗搧') - return - } - if (props.isSelectSku && selectedSkuIds.value.length === 0) { - message.warning('娌℃湁閫夋嫨浠讳綍鍟嗗搧灞炴��') - return - } - // 杩斿洖鍚勮嚜 id 鍒楄〃 - props.isSelectSku - ? emits('confirm', selectedSpuId.value, selectedSkuIds.value) - : emits('confirm', selectedSpuId.value) - // 鍏抽棴寮圭獥 - dialogVisible.value = false - selectedSpuId.value = 0 - selectedSkuIds.value = [] -} - -/** 鎵撳紑寮圭獥 */ -const open = () => { - dialogTitle.value = '鍟嗗搧閫夋嫨' - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ProductSpuApi.getSpuPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryParams.value = { - pageNo: 1, - pageSize: 10, - tabType: 0, // 榛樿鑾峰彇涓婃灦鐨勫晢鍝� - name: '', - categoryId: null, - createTime: [] - } - getList() -} - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - zIndex: 99999999, - urlList: [imgUrl] - }) -} - -const categoryList = ref() // 鍒嗙被鏍� - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱鍒嗙被鏍� - const data = await ProductCategoryApi.getCategoryList({}) - categoryList.value = handleTree(data, 'id', 'parentId') -}) -</script> diff --git a/src/views/mall/promotion/components/index.ts b/src/views/mall/promotion/components/index.ts deleted file mode 100644 index b42c8ce..0000000 --- a/src/views/mall/promotion/components/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import SpuSelect from './SpuSelect.vue' -import SpuAndSkuList from './SpuAndSkuList.vue' -import { PropertyAndValues } from '@/views/mall/product/spu/components' - -type SpuProperty<T> = { - spuId: number - spuDetail: T - propertyList: PropertyAndValues[] -} - -/** - * 鎻愪緵鍟嗗搧娲诲姩鍟嗗搧閫夋嫨閫氱敤缁勪欢 - */ -export { SpuSelect, SpuAndSkuList, SpuProperty } diff --git a/src/views/mall/promotion/coupon/components/CouponSelect.vue b/src/views/mall/promotion/coupon/components/CouponSelect.vue deleted file mode 100644 index 715dcb7..0000000 --- a/src/views/mall/promotion/coupon/components/CouponSelect.vue +++ /dev/null @@ -1,219 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%"> - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="82px" - > - <el-form-item label="浼樻儬鍒稿悕绉�" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヤ紭鎯犲姷鍚�" - @keyup="handleQuery" - /> - </el-form-item> - <el-form-item label="浼樻儬绫诲瀷" prop="discountType"> - <el-select - v-model="queryParams.discountType" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨浼樻儬鍒哥被鍨�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="浼樻儬鍒哥姸鎬�" prop="status"> - <el-select - v-model="queryParams.status" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨浼樻儬鍒哥姸鎬�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange"> - <el-table-column type="selection" width="55" /> - <el-table-column label="浼樻儬鍒稿悕绉�" min-width="140" prop="name" /> - <el-table-column label="绫诲瀷" min-width="80" prop="productScope"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_PRODUCT_SCOPE" :value="scope.row.productScope" /> - </template> - </el-table-column> - <el-table-column label="浼樻儬" min-width="100" prop="discount"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" /> - {{ discountFormat(scope.row) }} - </template> - </el-table-column> - <el-table-column label="棰嗗彇鏂瑰紡" min-width="100" prop="takeType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" /> - </template> - </el-table-column> - <el-table-column - :formatter="validityTypeFormat" - align="center" - label="浣跨敤鏃堕棿" - prop="validityType" - width="185" - /> - <el-table-column align="center" label="鍙戞斁鏁伴噺" prop="totalCount" /> - <el-table-column - :formatter="remainedCountFormat" - align="center" - label="鍓╀綑鏁伴噺" - prop="totalCount" - /> - <el-table-column - :formatter="takeLimitCountFormat" - align="center" - label="棰嗗彇涓婇檺" - prop="takeLimitCount" - /> - <el-table-column align="center" label="鐘舵��" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { - discountFormat, - remainedCountFormat, - takeLimitCountFormat, - validityTypeFormat -} from '@/views/mall/promotion/coupon/formatter' -import { dateFormatter } from '@/utils/formatTime' -import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' - -defineOptions({ name: 'CouponSelect' }) - -defineProps<{ - multipleSelection: CouponTemplateApi.CouponTemplateVO[] -}>() -const emit = defineEmits<{ - (e: 'update:multipleSelection', v: CouponTemplateApi.CouponTemplateVO[]) -}>() -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('閫夋嫨浼樻儬鍗�') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 瀛楀吀琛ㄦ牸鏁版嵁 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null, - discountType: null, - type: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 鎵ц鏌ヨ - const data = await CouponTemplateApi.getCouponTemplatePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef?.value?.resetFields() - handleQuery() -} - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - dialogVisible.value = true - resetQuery() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -const handleSelectionChange = (val: CouponTemplateApi.CouponTemplateVO[]) => { - emit('update:multipleSelection', val) -} - -const submitForm = () => { - dialogVisible.value = false -} -// TODO @puhui999锛氭彁鍓� todo锛屽厛涓嶇敤鏀癸紱鏈潵鍗曠嫭鎴愮粍浠讹紝鍏跺畠妯″潡鍙互鏈嶇敤锛涗緥濡傝锛屾弧鍑忛�侊紝鍙互閫夋嫨浼樻儬鍔碉紱 -</script> diff --git a/src/views/mall/promotion/coupon/components/CouponSendForm.vue b/src/views/mall/promotion/coupon/components/CouponSendForm.vue deleted file mode 100644 index be0223a..0000000 --- a/src/views/mall/promotion/coupon/components/CouponSendForm.vue +++ /dev/null @@ -1,162 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :appendToBody="true" title="鍙戦�佷紭鎯犲埜" width="70%"> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="82px" - > - <el-form-item label="浼樻儬鍒稿悕绉�" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - placeholder="璇疯緭鍏ヤ紭鎯犲姷鍚�" - clearable - @keyup="handleQuery" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - - <!-- 鍒楄〃 --> - <el-table v-loading="loading" :data="list" show-overflow-tooltip> - <el-table-column align="center" label="浼樻儬鍒稿悕绉�" prop="name" min-width="60" /> - <el-table-column - label="浼樻儬閲戦 / 鎶樻墸" - align="center" - prop="discount" - :formatter="discountFormat" - min-width="60" - /> - <el-table-column - align="center" - label="鏈�浣庢秷璐�" - prop="usePrice" - min-width="60" - :formatter="usePriceFormat" - /> - <el-table-column - align="center" - label="鏈夋晥鏈熼檺" - prop="validityType" - min-width="140" - :formatter="validityTypeFormat" - /> - <el-table-column - align="center" - label="鍓╀綑鏁伴噺" - min-width="60" - :formatter="remainedCountFormat" - /> - <el-table-column label="鎿嶄綔" align="center" min-width="60px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - :disabled="sendLoading" - :loading="sendLoading" - @click="handleSendCoupon(scope.row.id)" - v-hasPermi="['member:level:update']" - > - 鍙戦�� - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - <div class="clear-both"></div> - </Dialog> -</template> -<script lang="ts" setup> -import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' -import * as CouponApi from '@/api/mall/promotion/coupon/coupon' -import { - discountFormat, - remainedCountFormat, - usePriceFormat, - validityTypeFormat -} from '@/views/mall/promotion/coupon/formatter' -import { CouponTemplateTakeTypeEnum } from '@/utils/constants' - -defineOptions({ name: 'PromotionCouponSendForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const sendLoading = ref(false) // 鍙戦�佹寜閽殑鍔犺浇涓� -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - name: null, - canTakeTypes: [CouponTemplateTakeTypeEnum.ADMIN.type] -}) // 鏌ヨ鍙傛暟 -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -// 棰嗗彇浜虹殑缂栧彿鍒楄〃 -let userIds: number[] = [] - -/** 鎵撳紑寮圭獥 */ -const open = (ids: number[]) => { - userIds = ids - // 鎵撳紑鏃堕噸缃煡璇紝闃叉鍙戦�佸垪琛ㄥ墿浣欐暟閲忔湭鏇存柊鐨勯棶棰� - resetQuery() - - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await CouponTemplateApi.getCouponTemplatePage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef?.value?.resetFields() - handleQuery() -} - -/** 鍙戦�佹搷浣� **/ -const handleSendCoupon = async (templateId: number) => { - try { - sendLoading.value = true - await CouponApi.sendCoupon({ templateId, userIds }) - // 鎻愮ず - message.success('鍙戦�佹垚鍔�') - dialogVisible.value = false - } finally { - sendLoading.value = false - } -} -</script> diff --git a/src/views/mall/promotion/coupon/components/index.ts b/src/views/mall/promotion/coupon/components/index.ts deleted file mode 100644 index 6a0e56f..0000000 --- a/src/views/mall/promotion/coupon/components/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import CouponSendForm from './CouponSendForm.vue' -import CouponSelect from './CouponSelect.vue' - -export { CouponSendForm, CouponSelect } diff --git a/src/views/mall/promotion/coupon/formatter.ts b/src/views/mall/promotion/coupon/formatter.ts deleted file mode 100644 index f00138a..0000000 --- a/src/views/mall/promotion/coupon/formatter.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { CouponTemplateValidityTypeEnum, PromotionDiscountTypeEnum } from '@/utils/constants' -import { formatDate } from '@/utils/formatTime' -import { CouponTemplateVO } from '@/api/mall/promotion/coupon/couponTemplate' -import { floatToFixed2 } from '@/utils' - -// 鏍煎紡鍖栥�愪紭鎯犻噾棰�/鎶樻墸銆� -export const discountFormat = (row: CouponTemplateVO) => { - if (row.discountType === PromotionDiscountTypeEnum.PRICE.type) { - return `锟�${floatToFixed2(row.discountPrice)}` - } - if (row.discountType === PromotionDiscountTypeEnum.PERCENT.type) { - return `${row.discountPercent}%` - } - return '鏈煡銆�' + row.discountType + '銆�' -} - -// 鏍煎紡鍖栥�愰鍙栦笂闄愩�� -export const takeLimitCountFormat = (row: CouponTemplateVO) => { - if (row.takeLimitCount === -1) { - return '鏃犻鍙栭檺鍒�' - } - return `${row.takeLimitCount} 寮�/浜篳 -} - -// 鏍煎紡鍖栥�愭湁鏁堟湡闄愩�� -export const validityTypeFormat = (row: CouponTemplateVO) => { - if (row.validityType === CouponTemplateValidityTypeEnum.DATE.type) { - return `${formatDate(row.validStartTime)} 鑷� ${formatDate(row.validEndTime)}` - } - if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) { - return `棰嗗彇鍚庣 ${row.fixedStartTerm} - ${row.fixedEndTerm} 澶╁唴鍙敤` - } - return '鏈煡銆�' + row.validityType + '銆�' -} - -// 鏍煎紡鍖栥�愬墿浣欐暟閲忋�� -export const remainedCountFormat = (row: CouponTemplateVO) => { - return row.totalCount - row.takeCount -} - -// 鏍煎紡鍖栥�愭渶浣庢秷璐广�� -export const usePriceFormat = (row: CouponTemplateVO) => { - return `锟�${floatToFixed2(row.usePrice)}` -} diff --git a/src/views/mall/promotion/coupon/index.vue b/src/views/mall/promotion/coupon/index.vue deleted file mode 100755 index 25d2e94..0000000 --- a/src/views/mall/promotion/coupon/index.vue +++ /dev/null @@ -1,201 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戜紭鎯犲姷" url="https://doc.iocoder.cn/mall/promotion-coupon/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="浼氬憳鏄电О" prop="nickname"> - <el-input - v-model="queryParams.nickname" - class="!w-240px" - placeholder="璇疯緭鍏ヤ細鍛樻樀绉�" - clearable - @keyup="handleQuery" - /> - </el-form-item> - <el-form-item label="棰嗗彇鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" />鎼滅储 </el-button> - <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" />閲嶇疆 </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <!-- Tab 閫夐」锛氱湡姝g殑鍐呭鍦� Lab --> - <el-tabs v-model="activeTab" type="card" @tab-change="onTabChange"> - <el-tab-pane - v-for="tab in statusTabs" - :key="tab.value" - :label="tab.label" - :name="tab.value" - /> - </el-tabs> - - <!-- 鍒楄〃 --> - <el-table v-loading="loading" :data="list"> - <el-table-column label="浼氬憳鏄电О" align="center" min-width="100" prop="nickname" /> - <el-table-column label="浼樻儬鍒稿悕绉�" align="center" min-width="140" prop="name" /> - <el-table-column label="绫诲瀷" align="center" prop="discountType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_PRODUCT_SCOPE" :value="scope.row.productScope" /> - </template> - </el-table-column> - <el-table-column label="浼樻儬" min-width="100" prop="discount"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" /> - {{ discountFormat(scope.row) }} - </template> - </el-table-column> - <el-table-column label="棰嗗彇鏂瑰紡" align="center" prop="takeType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" /> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="棰嗗彇鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column - label="浣跨敤鏃堕棿" - align="center" - prop="useTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:coupon:delete']" - type="danger" - link - @click="handleDelete(scope.row.id)" - > - 鍥炴敹 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts" name="PromotionCoupon"> -import { deleteCoupon, getCouponPage } from '@/api/mall/promotion/coupon/coupon' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { discountFormat } from '@/views/mall/promotion/coupon/formatter' - -defineOptions({ name: 'PromotionCoupon' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 瀛楀吀琛ㄦ牸鏁版嵁 -// 鏌ヨ鍙傛暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - createTime: [], - status: undefined, - nickname: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -const activeTab = ref('all') // Tab 绛涢�� -const statusTabs = reactive([ - { - label: '鍏ㄩ儴', - value: 'all' - } -]) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - // 鎵ц鏌ヨ - try { - const data = await getCouponPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 浜屾纭 - await message.confirm( - '鍥炴敹灏嗕細鏀跺洖浼氬憳棰嗗彇鐨勫緟浣跨敤鐨勪紭鎯犲埜锛屽凡浣跨敤鐨勫皢鏃犳硶鍥炴敹锛岀‘瀹氳鍥炴敹鎵�閫変紭鎯犲埜鍚楋紵' - ) - // 鍙戣捣鍒犻櫎 - await deleteCoupon(id) - message.notifySuccess('鍥炴敹鎴愬姛') - // 閲嶆柊鍔犺浇鍒楄〃 - await getList() - } catch {} -} - -/** tab 鍒囨崲 */ -const onTabChange = (tabName) => { - queryParams.status = tabName === 'all' ? undefined : tabName - getList() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() - // 璁剧疆 statuses 杩囨护 - for (const dict of getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_STATUS)) { - statusTabs.push({ - label: dict.label, - value: dict.value as string - }) - } -}) -</script> diff --git a/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue b/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue deleted file mode 100644 index 408f381..0000000 --- a/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue +++ /dev/null @@ -1,388 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="140px" - > - <el-form-item label="浼樻儬鍒稿悕绉�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ヤ紭鎯犲埜鍚嶇О" /> - </el-form-item> - <el-form-item label="浼樻儬鍔电被鍨�" prop="productScope"> - <el-radio-group v-model="formData.productScope"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item - v-if="formData.productScope === PromotionProductScopeEnum.SPU.scope" - label="鍟嗗搧" - prop="productSpuIds" - > - <SpuShowcase v-model="formData.productSpuIds" /> - </el-form-item> - <el-form-item - v-if="formData.productScope === PromotionProductScopeEnum.CATEGORY.scope" - label="鍒嗙被" - prop="productCategoryIds" - > - <ProductCategorySelect v-model="formData.productCategoryIds" /> - </el-form-item> - <el-form-item label="浼樻儬绫诲瀷" prop="discountType"> - <el-radio-group v-model="formData.discountType"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item - v-if="formData.discountType === PromotionDiscountTypeEnum.PRICE.type" - label="浼樻儬鍒搁潰棰�" - prop="discountPrice" - > - <el-input-number - v-model="formData.discountPrice" - :min="0" - :precision="2" - class="mr-2 !w-400px" - placeholder="璇疯緭鍏ヤ紭鎯犻噾棰濓紝鍗曚綅锛氬厓" - /> - 鍏� - </el-form-item> - <el-form-item - v-if="formData.discountType === PromotionDiscountTypeEnum.PERCENT.type" - label="浼樻儬鍒告姌鎵�" - prop="discountPercent" - > - <el-input-number - v-model="formData.discountPercent" - :max="9.9" - :min="1" - :precision="1" - class="mr-2 !w-400px" - placeholder="浼樻儬鍒告姌鎵d笉鑳藉皬浜� 1 鎶橈紝涓斾笉鍙ぇ浜� 9.9 鎶�" - /> - 鎶� - </el-form-item> - <el-form-item - v-if="formData.discountType === PromotionDiscountTypeEnum.PERCENT.type" - label="鏈�澶氫紭鎯�" - prop="discountLimitPrice" - > - <el-input-number - v-model="formData.discountLimitPrice" - :min="0" - :precision="2" - class="mr-2 !w-400px" - placeholder="璇疯緭鍏ユ渶澶氫紭鎯�" - /> - 鍏� - </el-form-item> - <el-form-item label="婊″灏戝厓鍙互浣跨敤" prop="usePrice"> - <el-input-number - v-model="formData.usePrice" - :min="0" - :precision="2" - class="mr-2 !w-400px" - placeholder="鏃犻棬妲涜璁句负 0" - /> - 鍏� - </el-form-item> - <el-form-item label="棰嗗彇鏂瑰紡" prop="takeType"> - <el-radio-group v-model="formData.takeType"> - <el-radio :key="1" :label="1">鐩存帴棰嗗彇</el-radio> - <el-radio :key="2" :label="2">鎸囧畾鍙戞斁</el-radio> - </el-radio-group> - </el-form-item> - <el-form-item v-if="formData.takeType === 1" label="鍙戞斁鏁伴噺" prop="totalCount"> - <el-input-number - v-model="formData.totalCount" - :min="-1" - :precision="0" - class="mr-2 !w-400px" - placeholder="鍙戞斁鏁伴噺锛屾病鏈変箣鍚庝笉鑳介鍙栨垨鍙戞斁锛�-1 涓轰笉闄愬埗" - /> - 寮� - </el-form-item> - <el-form-item v-if="formData.takeType === 1" label="姣忎汉闄愰涓暟" prop="takeLimitCount"> - <el-input-number - v-model="formData.takeLimitCount" - :min="-1" - :precision="0" - class="mr-2 !w-400px" - placeholder="璁剧疆涓� -1 鏃讹紝鍙棤闄愰鍙�" - /> - 寮� - </el-form-item> - <el-form-item label="鏈夋晥鏈熺被鍨�" prop="validityType"> - <el-radio-group v-model="formData.validityType"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item - v-if="formData.validityType === CouponTemplateValidityTypeEnum.DATE.type" - label="鍥哄畾鏃ユ湡" - prop="validTimes" - > - <el-date-picker - v-model="formData.validTimes" - :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]" - style="width: 240px" - type="datetimerange" - value-format="x" - /> - </el-form-item> - <el-form-item - v-if="formData.validityType === CouponTemplateValidityTypeEnum.TERM.type" - label="棰嗗彇鏃ユ湡" - prop="fixedStartTerm" - > - 绗� - <el-input-number - v-model="formData.fixedStartTerm" - :min="0" - :precision="0" - class="mx-2" - placeholder="0 涓轰粖澶╃敓鏁�" - /> - 鑷� - <el-input-number - v-model="formData.fixedEndTerm" - :min="0" - :precision="0" - class="mx-2" - placeholder="璇疯緭鍏ョ粨鏉熷ぉ鏁�" - /> - 澶╂湁鏁� - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' -import { - CouponTemplateValidityTypeEnum, - PromotionDiscountTypeEnum, - PromotionProductScopeEnum -} from '@/utils/constants' -import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue' -import ProductCategorySelect from '@/views/mall/product/category/components/ProductCategorySelect.vue' -import { convertToInteger, formatToFraction } from '@/utils' - -defineOptions({ name: 'CouponTemplateForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - discountType: PromotionDiscountTypeEnum.PRICE.type, - discountPrice: undefined, - discountPercent: undefined, - discountLimitPrice: undefined, - usePrice: undefined, - takeType: 1, - totalCount: undefined, - takeLimitCount: undefined, - validityType: CouponTemplateValidityTypeEnum.DATE.type, - validTimes: [], - validStartTime: undefined, - validEndTime: undefined, - fixedStartTerm: undefined, - fixedEndTerm: undefined, - productScope: PromotionProductScopeEnum.ALL.scope, - productScopeValues: [], // 鍟嗗搧鑼冨洿锛氬�间负 鍝佺被缂栧彿鍒楄〃 鎴� 鍟嗗搧缂栧彿鍒楄〃 锛岀敤浜庢彁浜� - productCategoryIds: [], // 浠呯敤浜庤〃鍗曪紝涓嶆彁浜� - productSpuIds: [] // 浠呯敤浜庤〃鍗曪紝涓嶆彁浜� -}) -const formRules = reactive({ - name: [{ required: true, message: '浼樻儬鍒稿悕绉颁笉鑳戒负绌�', trigger: 'blur' }], - discountType: [{ required: true, message: '浼樻儬鍒哥被鍨嬩笉鑳戒负绌�', trigger: 'change' }], - discountPrice: [{ required: true, message: '浼樻儬鍒搁潰棰濅笉鑳戒负绌�', trigger: 'blur' }], - discountPercent: [{ required: true, message: '浼樻儬鍒告姌鎵d笉鑳戒负绌�', trigger: 'blur' }], - discountLimitPrice: [{ required: true, message: '鏈�澶氫紭鎯犱笉鑳戒负绌�', trigger: 'blur' }], - usePrice: [{ required: true, message: '婊″灏戝厓鍙互浣跨敤涓嶈兘涓虹┖', trigger: 'blur' }], - takeType: [{ required: true, message: '棰嗗彇鏂瑰紡涓嶈兘涓虹┖', trigger: 'change' }], - totalCount: [{ required: true, message: '鍙戞斁鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' }], - takeLimitCount: [{ required: true, message: '姣忎汉闄愰涓暟涓嶈兘涓虹┖', trigger: 'blur' }], - validityType: [{ required: true, message: '鏈夋晥鏈熺被鍨嬩笉鑳戒负绌�', trigger: 'change' }], - validTimes: [{ required: true, message: '鍥哄畾鏃ユ湡涓嶈兘涓虹┖', trigger: 'change' }], - fixedStartTerm: [{ required: true, message: '寮�濮嬮鍙栧ぉ鏁颁笉鑳戒负绌�', trigger: 'blur' }], - fixedEndTerm: [{ required: true, message: '寮�濮嬮鍙栧ぉ鏁颁笉鑳戒负绌�', trigger: 'blur' }], - productScope: [{ required: true, message: '鍟嗗搧鑼冨洿涓嶈兘涓虹┖', trigger: 'blur' }], - productSpuIds: [{ required: true, message: '鍟嗗搧涓嶈兘涓虹┖', trigger: 'blur' }], - productCategoryIds: [{ required: true, message: '鍒嗙被涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = await CouponTemplateApi.getCouponTemplate(id) - formData.value = { - ...data, - discountPrice: formatToFraction(data.discountPrice), - discountPercent: - data.discountPercent !== undefined ? data.discountPercent / 10.0 : undefined, - discountLimitPrice: formatToFraction(data.discountLimitPrice), - usePrice: formatToFraction(data.usePrice), - validTimes: [data.validStartTime, data.validEndTime] - } - // 鑾峰緱鍟嗗搧鑼冨洿 - await getProductScope() - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { - ...formData.value, - discountPrice: convertToInteger(formData.value.discountPrice), - discountPercent: - formData.value.discountPercent !== undefined - ? formData.value.discountPercent * 10 - : undefined, - discountLimitPrice: convertToInteger(formData.value.discountLimitPrice), - usePrice: convertToInteger(formData.value.usePrice), - validStartTime: - formData.value.validTimes && formData.value.validTimes.length === 2 - ? formData.value.validTimes[0] - : undefined, - validEndTime: - formData.value.validTimes && formData.value.validTimes.length === 2 - ? formData.value.validTimes[1] - : undefined - } as unknown as CouponTemplateApi.CouponTemplateVO - - // 璁剧疆鍟嗗搧鑼冨洿 - setProductScopeValues(data) - - if (formType.value === 'create') { - await CouponTemplateApi.createCouponTemplate(data) - message.success(t('common.createSuccess')) - } else { - await CouponTemplateApi.updateCouponTemplate(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - discountType: PromotionDiscountTypeEnum.PRICE.type, - discountPrice: undefined, - discountPercent: undefined, - discountLimitPrice: undefined, - usePrice: undefined, - takeType: 1, - totalCount: undefined, - takeLimitCount: undefined, - validityType: CouponTemplateValidityTypeEnum.DATE.type, - validTimes: [], - validStartTime: undefined, - validEndTime: undefined, - fixedStartTerm: undefined, - fixedEndTerm: undefined, - productScope: PromotionProductScopeEnum.ALL.scope, - productScopeValues: [], - productSpuIds: [], - productCategoryIds: [] - } - formRef.value?.resetFields() -} - -/** 鑾峰緱鍟嗗搧鑼冨洿 */ -const getProductScope = async () => { - switch (formData.value.productScope) { - case PromotionProductScopeEnum.SPU.scope: - // 璁剧疆鍟嗗搧缂栧彿 - formData.value.productSpuIds = formData.value.productScopeValues - break - case PromotionProductScopeEnum.CATEGORY.scope: - await nextTick(() => { - let productCategoryIds = formData.value.productScopeValues - if (Array.isArray(productCategoryIds) && productCategoryIds.length > 0) { - // 鍗曢�夋椂浣跨敤鏁扮粍涓嶈兘鍙嶆樉 - productCategoryIds = productCategoryIds[0] - } - // 璁剧疆鍝佺被缂栧彿 - formData.value.productCategoryIds = productCategoryIds - }) - break - default: - break - } -} - -/** 璁剧疆鍟嗗搧鑼冨洿 */ -function setProductScopeValues(data: CouponTemplateApi.CouponTemplateVO) { - switch (formData.value.productScope) { - case PromotionProductScopeEnum.SPU.scope: - data.productScopeValues = formData.value.productSpuIds - break - case PromotionProductScopeEnum.CATEGORY.scope: - data.productScopeValues = Array.isArray(formData.value.productCategoryIds) - ? formData.value.productCategoryIds - : [formData.value.productCategoryIds] - break - default: - break - } -} -</script> - -<style lang="scss" scoped></style> diff --git a/src/views/mall/promotion/coupon/template/index.vue b/src/views/mall/promotion/coupon/template/index.vue deleted file mode 100755 index 657cead..0000000 --- a/src/views/mall/promotion/coupon/template/index.vue +++ /dev/null @@ -1,278 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戜紭鎯犲姷" url="https://doc.iocoder.cn/mall/promotion-coupon/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="82px" - > - <el-form-item label="浼樻儬鍒稿悕绉�" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ヤ紭鎯犲姷鍚�" - @keyup="handleQuery" - /> - </el-form-item> - <el-form-item label="浼樻儬绫诲瀷" prop="discountType"> - <el-select - v-model="queryParams.discountType" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨浼樻儬鍒哥被鍨�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="浼樻儬鍒哥姸鎬�" prop="status"> - <el-select - v-model="queryParams.status" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨浼樻儬鍒哥姸鎬�" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['promotion:coupon-template:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="浼樻儬鍒稿悕绉�" min-width="140" prop="name" /> - <el-table-column label="绫诲瀷" min-width="130" prop="productScope"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_PRODUCT_SCOPE" :value="scope.row.productScope" /> - </template> - </el-table-column> - <el-table-column label="浼樻儬" min-width="110" prop="discount"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" /> - <div>{{ discountFormat(scope.row) }}</div> - </template> - </el-table-column> - <el-table-column label="棰嗗彇鏂瑰紡" min-width="100" prop="takeType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" /> - </template> - </el-table-column> - <el-table-column - :formatter="validityTypeFormat" - align="center" - label="浣跨敤鏃堕棿" - prop="validityType" - width="185" - /> - <el-table-column align="center" label="鍙戞斁鏁伴噺" prop="totalCount" /> - <el-table-column - :formatter="remainedCountFormat" - align="center" - label="鍓╀綑鏁伴噺" - prop="totalCount" - /> - <el-table-column - :formatter="takeLimitCountFormat" - align="center" - label="棰嗗彇涓婇檺" - prop="takeLimitCount" - /> - <el-table-column align="center" label="鐘舵��" prop="status"> - <template #default="scope"> - <el-switch - v-model="scope.row.status" - :active-value="0" - :inactive-value="1" - @change="handleStatusChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column - align="center" - class-name="small-padding fixed-width" - fixed="right" - label="鎿嶄綔" - width="120" - > - <template #default="scope"> - <el-button - v-hasPermi="['promotion:coupon-template:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 淇敼 - </el-button> - <el-button - v-hasPermi="['promotion:coupon-template:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <CouponTemplateForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import CouponTemplateForm from './CouponTemplateForm.vue' -import { - discountFormat, - remainedCountFormat, - takeLimitCountFormat, - validityTypeFormat -} from '@/views/mall/promotion/coupon/formatter' - -defineOptions({ name: 'PromotionCouponTemplate' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 瀛楀吀琛ㄦ牸鏁版嵁 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null, - discountType: null, - type: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 鎵ц鏌ヨ - const data = await CouponTemplateApi.getCouponTemplatePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef?.value?.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 浼樻儬鍔垫ā鏉跨姸鎬佷慨鏀� */ -const handleStatusChange = async (row: any) => { - // 姝ゆ椂锛宺ow 宸茬粡鍙樻垚鐩爣鐘舵�佷簡锛屾墍浠ュ彲浠ョ洿鎺ユ彁浜よ姹傚拰鎻愮ず - let text = row.status === CommonStatusEnum.ENABLE ? '鍚敤' : '鍋滅敤' - - try { - await message.confirm('纭瑕�"' + text + '""' + row.name + '"浼樻儬鍔靛悧?') - await CouponTemplateApi.updateCouponTemplateStatus(row.id, row.status) - message.success(text + '鎴愬姛') - } catch { - // 寮傚父鏃讹紝闇�瑕佸皢 row.status 鐘舵�侀噸缃洖涔嬪墠鐨� - row.status = - row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE - } -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.confirm('鏄惁纭鍒犻櫎浼樻儬鍔电紪鍙蜂负"' + id + '"鐨勬暟鎹」?') - // 鍙戣捣鍒犻櫎 - await CouponTemplateApi.deleteCouponTemplate(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/discountActivity/DiscountActivityForm.vue b/src/views/mall/promotion/discountActivity/DiscountActivityForm.vue deleted file mode 100644 index d7a9806..0000000 --- a/src/views/mall/promotion/discountActivity/DiscountActivityForm.vue +++ /dev/null @@ -1,179 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%"> - <Form - ref="formRef" - v-loading="formLoading" - :isCol="true" - :rules="rules" - :schema="allSchemas.formSchema" - > - <!-- 鍏堥�夋嫨 --> - <!-- TODO @zhangshuai锛氬晢鍝佸厑璁搁�夋嫨澶氫釜 --> - <!-- TODO @zhangshuai锛氶�夋嫨鍚庣殑 SKU锛岄渶瑕佸悗闈㈠姞涓�愬垹闄ゃ�戞寜閽� --> - <!-- TODO @zhangshuai锛氬睍绀虹殑閲戦锛岃矊浼间笉瀵癸紝澶т簡 100 鍊嶏紝闇�瑕佺湅涓� --> - <!-- TODO @zhangshuai锛氣�滀紭鎯犵被鍨嬧�濓紝鏄瘡涓� SKU 鍙互鑷畾涔夊凡璁剧疆鍝堛�傚洜涓烘瘡涓晢鍝� SKU 鐨勬姌鎵e拰鍑忓皯浠锋牸锛屽彲鑳戒笉鍚屻�傚叿浣撲氦浜掞紝鍙互娉ㄥ唽涓�涓� youzan.com 鐪嬬湅锛涘畠鐨勪氦浜掓柟寮忔槸锛屽鏋滆缃簡鈥滀紭鎯犻噾棰濃�濓紝鍒欑畻鈥滃噺浠封�濓紱濡傛灉鍐嶆璁剧疆浜嗏�滄姌鎵g櫨鍒嗘瘮鈥濓紝灏辩畻鈥滄墦鎶樷�濓紱杩欐牱褰㈡垚涓�涓簰鏂ョ殑浼樻儬绫诲瀷 --> - <template #spuId> - <el-button @click="spuSelectRef.open()">閫夋嫨鍟嗗搧</el-button> - <SpuAndSkuList - ref="spuAndSkuListRef" - :rule-config="ruleConfig" - :spu-list="spuList" - :spu-property-list-p="spuPropertyList" - > - <el-table-column align="center" label="浼樻儬閲戦" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number v-model="sku.productConfig.discountPrice" :min="0" class="w-100%" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎶樻墸鐧惧垎姣�(%)" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number v-model="sku.productConfig.discountPercent" class="w-100%" /> - </template> - </el-table-column> - </SpuAndSkuList> - </template> - </Form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SpuSelect ref="spuSelectRef" :isSelectSku="true" @confirm="selectSpu" /> -</template> -<script lang="ts" setup> -import { SpuAndSkuList, SpuProperty, SpuSelect } from '../components' -import { allSchemas, rules } from './discountActivity.data' -import { cloneDeep } from 'lodash-es' -import * as DiscountActivityApi from '@/api/mall/promotion/discount/discountActivity' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' - -defineOptions({ name: 'PromotionDiscountActivityForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formRef = ref() // 琛ㄥ崟 Ref -// ================= 鍟嗗搧閫夋嫨鐩稿叧 ================= - -const spuSelectRef = ref() // 鍟嗗搧鍜屽睘鎬ч�夋嫨 Ref -const spuAndSkuListRef = ref() // sku 闄愭椂鎶樻墸 閰嶇疆缁勪欢Ref -const ruleConfig: RuleConfig[] = [] -const spuList = ref<DiscountActivityApi.SpuExtension[]>([]) // 閫夋嫨鐨� spu -const spuPropertyList = ref<SpuProperty<DiscountActivityApi.SpuExtension>[]>([]) -const selectSpu = (spuId: number, skuIds: number[]) => { - formRef.value.setValues({ spuId }) - getSpuDetails(spuId, skuIds) -} -/** - * 鑾峰彇 SPU 璇︽儏 - */ -const getSpuDetails = async ( - spuId: number, - skuIds: number[] | undefined, - products?: DiscountActivityApi.DiscountProductVO[] -) => { - const spuProperties: SpuProperty<DiscountActivityApi.SpuExtension>[] = [] - const res = (await ProductSpuApi.getSpuDetailList([spuId])) as DiscountActivityApi.SpuExtension[] - if (res.length == 0) { - return - } - spuList.value = [] - // 鍥犱负鍙兘閫夋嫨涓�涓� - const spu = res[0] - const selectSkus = - typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!)) - selectSkus?.forEach((sku) => { - let config: DiscountActivityApi.DiscountProductVO = { - skuId: sku.id!, - spuId: spu.id, - discountType: 1, - discountPercent: 0, - discountPrice: 0 - } - if (typeof products !== 'undefined') { - const product = products.find((item) => item.skuId === sku.id) - config = product || config - } - sku.productConfig = config - }) - spu.skus = selectSkus as DiscountActivityApi.SkuExtension[] - spuProperties.push({ - spuId: spu.id!, - spuDetail: spu, - propertyList: getPropertyList(spu) - }) - spuList.value.push(spu) - spuPropertyList.value = spuProperties -} - -// ================= end ================= - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - await resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = (await DiscountActivityApi.getDiscountActivity( - id - )) as DiscountActivityApi.DiscountActivityVO - const supId = data.products[0].spuId - await getSpuDetails(supId!, data.products?.map((sku) => sku.skuId), data.products) - formRef.value.setValues(data) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.getElFormRef().validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formRef.value.formModel as DiscountActivityApi.DiscountActivityVO - // 鑾峰彇 鎶樻墸鍟嗗搧閰嶇疆 - const products = cloneDeep(spuAndSkuListRef.value.getSkuConfigs('productConfig')) - products.forEach((item: DiscountActivityApi.DiscountProductVO) => { - item.discountType = data['discountType'] - }) - data.products = products - // 鐪熸鎻愪氦 - if (formType.value === 'create') { - await DiscountActivityApi.createDiscountActivity(data) - message.success(t('common.createSuccess')) - } else { - await DiscountActivityApi.updateDiscountActivity(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = async () => { - spuList.value = [] - spuPropertyList.value = [] - await nextTick() - formRef.value.getElFormRef().resetFields() -} -</script> diff --git a/src/views/mall/promotion/discountActivity/discountActivity.data.ts b/src/views/mall/promotion/discountActivity/discountActivity.data.ts deleted file mode 100644 index d79dcab..0000000 --- a/src/views/mall/promotion/discountActivity/discountActivity.data.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { CrudSchema } from '@/hooks/web/useCrudSchemas' -import { dateFormatter2 } from '@/utils/formatTime' - -// TODO @zhangshai锛� -// 琛ㄥ崟鏍¢獙 -export const rules = reactive({ - spuId: [required], - name: [required], - startTime: [required], - endTime: [required], - discountType: [required] -}) - -// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ -const crudSchemas = reactive<CrudSchema[]>([ - { - label: '娲诲姩鍚嶇О', - field: 'name', - isSearch: true, - form: { - colProps: { - span: 24 - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩寮�濮嬫椂闂�', - field: 'startTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩缁撴潫鏃堕棿', - field: 'endTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '浼樻儬绫诲瀷', - field: 'discountType', - dictType: DICT_TYPE.PROMOTION_DISCOUNT_TYPE, - dictClass: 'number', - isSearch: true, - form: { - component: 'Radio', - value: 1 - } - }, - { - label: '娲诲姩鍟嗗搧', - field: 'spuId', - isTable: true, - isSearch: false, - form: { - colProps: { - span: 24 - } - }, - table: { - width: 300 - } - }, - { - label: '澶囨敞', - field: 'remark', - isSearch: false, - form: { - component: 'Input', - componentProps: { - type: 'textarea', - rows: 4 - }, - colProps: { - span: 24 - } - }, - table: { - width: 300 - } - } -]) -export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/src/views/mall/promotion/discountActivity/index.vue b/src/views/mall/promotion/discountActivity/index.vue deleted file mode 100644 index 7d73b51..0000000 --- a/src/views/mall/promotion/discountActivity/index.vue +++ /dev/null @@ -1,239 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戦檺鏃舵姌鎵�" url="https://doc.iocoder.cn/mall/promotion-discount/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="娲诲姩鏃堕棿" prop="activeTime"> - <el-date-picker - v-model="queryParams.activeTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:discount-activity:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板娲诲姩 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="娲诲姩缂栧彿" prop="id" min-width="80" /> - <el-table-column label="娲诲姩鍚嶇О" prop="name" min-width="140" /> - <el-table-column label="娲诲姩鏃堕棿" min-width="210"> - <template #default="scope"> - {{ formatDate(scope.row.startTime, 'YYYY-MM-DD') }} - ~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }} - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍥剧墖" prop="spuName" min-width="80"> - <template #default="scope"> - <el-image - :src="scope.row.picUrl" - class="h-40px w-40px" - :preview-src-list="[scope.row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鏍囬" prop="spuName" min-width="300" /> - <el-table-column label="娲诲姩鐘舵��" align="center" prop="status" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:discount-activity:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleClose(scope.row.id)" - v-if="scope.row.status === 0" - v-hasPermi="['promotion:discount-activity:close']" - > - 鍏抽棴 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-else - v-hasPermi="['promotion:discount-activity:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <DiscountActivityForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as DiscountActivity from '@/api/mall/promotion/discount/discountActivity' -import DiscountActivityForm from './DiscountActivityForm.vue' -import { formatDate } from '@/utils/formatTime' -import { fenToYuanFormat } from '@/utils/formatter' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'DiscountActivity' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - activeTime: null, - name: null, - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DiscountActivity.getDiscountActivityPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍏抽棴鎸夐挳鎿嶄綔 */ -const handleClose = async (id: number) => { - try { - // 鍏抽棴鐨勪簩娆$‘璁� - await message.confirm('纭鍏抽棴璇ラ檺鏃舵姌鎵f椿鍔ㄥ悧锛�') - // 鍙戣捣鍏抽棴 - await DiscountActivity.closeDiscountActivity(id) - message.success('鍏抽棴鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DiscountActivity.deleteDiscountActivity(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -const configList = ref([]) // 鏃舵閰嶇疆绮剧畝鍒楄〃 -// const formatConfigNames = (configId) => { -// const config = configList.value.find((item) => item.id === configId) -// return config != null ? `${config.name}[${config.startTime} ~ ${config.endTime}]` : '' -// } - -const formatSeckillPrice = (products) => { - // const seckillPrice = Math.min(...products.map((item) => item.seckillPrice)) - console.log(products) - const seckillPrice = 200 - return `锟�${fenToYuan(seckillPrice)}` -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> diff --git a/src/views/mall/promotion/diy/page/DiyPageForm.vue b/src/views/mall/promotion/diy/page/DiyPageForm.vue deleted file mode 100644 index 4c47187..0000000 --- a/src/views/mall/promotion/diy/page/DiyPageForm.vue +++ /dev/null @@ -1,104 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="椤甸潰鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ラ〉闈㈠悕绉�" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - <el-form-item label="棰勮鍥�" prop="previewPicUrls"> - <UploadImgs v-model="formData.previewPicUrls" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as DiyPageApi from '@/api/mall/promotion/diy/page' - -/** 瑁呬慨椤甸潰琛ㄥ崟 */ -defineOptions({ name: 'DiyPageForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - remark: undefined, - previewPicUrls: [] -}) -const formRules = reactive({ - name: [{ required: true, message: '椤甸潰鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await DiyPageApi.getDiyPage(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as DiyPageApi.DiyPageVO - if (formType.value === 'create') { - await DiyPageApi.createDiyPage(data) - message.success(t('common.createSuccess')) - } else { - await DiyPageApi.updateDiyPage(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - remark: undefined, - previewPicUrls: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/promotion/diy/page/decorate.vue b/src/views/mall/promotion/diy/page/decorate.vue deleted file mode 100644 index fa20c3e..0000000 --- a/src/views/mall/promotion/diy/page/decorate.vue +++ /dev/null @@ -1,74 +0,0 @@ -<template> - <DiyEditor - v-if="formData && !formLoading" - v-model="formData.property" - :title="formData.name" - :libs="PAGE_LIBS" - @save="submitForm" - /> -</template> -<script setup lang="ts"> -import * as DiyPageApi from '@/api/mall/promotion/diy/page' -import { useTagsViewStore } from '@/store/modules/tagsView' -import { PAGE_LIBS } from '@/components/DiyEditor/util' - -/** 瑁呬慨椤甸潰琛ㄥ崟 */ -defineOptions({ name: 'DiyPageDecorate' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<DiyPageApi.DiyPageVO>() -const formRef = ref() // 琛ㄥ崟 Ref - -// 鑾峰彇璇︽儏 -const getPageDetail = async (id: any) => { - formLoading.value = true - try { - formData.value = await DiyPageApi.getDiyPageProperty(id) - } finally { - formLoading.value = false - } -} - -// 鎻愪氦琛ㄥ崟 -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await DiyPageApi.updateDiyPageProperty(unref(formData)!) - message.success('淇濆瓨鎴愬姛') - } finally { - formLoading.value = false - } -} - -// 閲嶇疆琛ㄥ崟 -const resetForm = () => { - formData.value = { - id: undefined, - templateId: undefined, - name: '', - remark: '', - previewPicUrls: [], - property: '' - } as DiyPageApi.DiyPageVO - formRef.value?.resetFields() -} - -/** 鍒濆鍖� **/ -const { currentRoute } = useRouter() // 璺敱 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const route = useRoute() -onMounted(() => { - resetForm() - if (!route.params.id) { - message.warning('鍙傛暟閿欒锛岄〉闈㈢紪鍙蜂笉鑳戒负绌猴紒') - delView(unref(currentRoute)) - return - } - getPageDetail(route.params.id) -}) -</script> diff --git a/src/views/mall/promotion/diy/page/index.vue b/src/views/mall/promotion/diy/page/index.vue deleted file mode 100644 index f225332..0000000 --- a/src/views/mall/promotion/diy/page/index.vue +++ /dev/null @@ -1,191 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戝晢鍩庤淇�" url="https://doc.iocoder.cn/mall/diy/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="椤甸潰鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ラ〉闈㈠悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:diy-page:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="棰勮鍥�" align="center" prop="previewPicUrls"> - <template #default="scope"> - <el-image - class="h-40px max-w-40px" - v-for="(url, index) in scope.row.previewPicUrls" - :key="index" - :src="url" - :preview-src-list="scope.row.previewPicUrls" - :initial-index="index" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="椤甸潰鍚嶇О" align="center" prop="name" /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="handleDecorate(scope.row.id)" - v-hasPermi="['promotion:diy-page:update']" - > - 瑁呬慨 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:diy-page:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['promotion:diy-page:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <DiyPageForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as DiyPageApi from '@/api/mall/promotion/diy/page' -import DiyPageForm from './DiyPageForm.vue' - -/** 瑁呬慨椤甸潰 */ -defineOptions({ name: 'DiyPage' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DiyPageApi.getDiyPagePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DiyPageApi.deleteDiyPage(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎵撳紑瑁呬慨椤甸潰 */ -const { push } = useRouter() -const handleDecorate = (id: number) => { - push({ name: 'DiyPageDecorate', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/diy/template/DiyTemplateForm.vue b/src/views/mall/promotion/diy/template/DiyTemplateForm.vue deleted file mode 100644 index f430d35..0000000 --- a/src/views/mall/promotion/diy/template/DiyTemplateForm.vue +++ /dev/null @@ -1,104 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item label="妯℃澘鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ユā鏉垮悕绉�" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> - </el-form-item> - <el-form-item label="棰勮鍥�" prop="previewPicUrls"> - <UploadImgs v-model="formData.previewPicUrls" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as DiyTemplateApi from '@/api/mall/promotion/diy/template' - -/** 瑁呬慨妯℃澘琛ㄥ崟 */ -defineOptions({ name: 'DiyTemplateForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - remark: undefined, - previewPicUrls: [] -}) -const formRules = reactive({ - name: [{ required: true, message: '妯℃澘鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await DiyTemplateApi.getDiyTemplate(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as DiyTemplateApi.DiyTemplateVO - if (formType.value === 'create') { - await DiyTemplateApi.createDiyTemplate(data) - message.success(t('common.createSuccess')) - } else { - await DiyTemplateApi.updateDiyTemplate(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - remark: undefined, - previewPicUrls: [] - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/promotion/diy/template/decorate.vue b/src/views/mall/promotion/diy/template/decorate.vue deleted file mode 100644 index e7838f2..0000000 --- a/src/views/mall/promotion/diy/template/decorate.vue +++ /dev/null @@ -1,167 +0,0 @@ -<template> - <DiyEditor - v-if="formData && !formLoading" - v-model="currentFormData!.property" - :title="templateItems[selectedTemplateItem].name" - :libs="libs" - :show-page-config="selectedTemplateItem !== 0" - :show-tab-bar="selectedTemplateItem === 0" - :show-navigation-bar="selectedTemplateItem !== 0" - :preview-url="previewUrl" - @save="submitForm" - @reset="handleEditorReset" - > - <template #toolBarLeft> - <el-radio-group - v-model="selectedTemplateItem" - class="h-full!" - @change="handleTemplateItemChange" - > - <el-tooltip v-for="(item, index) in templateItems" :key="index" :content="item.name"> - <el-radio-button :label="index"> - <Icon :icon="item.icon" :size="24" /> - </el-radio-button> - </el-tooltip> - </el-radio-group> - </template> - </DiyEditor> -</template> -<script setup lang="ts"> -// TODO @鐤媯锛氳涓嶈寤轰釜 decorate 鐩綍锛岀劧鍚庢尓杩涘幓锛屾敼鎴� index.vue锛岃繖鏍峰彲浠ユ洿鏄庣‘鐪嬪埌鏄釜鐙珛鐣岄潰鍝堬紝鏇村ソ鎵� -import * as DiyTemplateApi from '@/api/mall/promotion/diy/template' -import * as DiyPageApi from '@/api/mall/promotion/diy/page' -import { useTagsViewStore } from '@/store/modules/tagsView' -import { DiyComponentLibrary, PAGE_LIBS } from '@/components/DiyEditor/util' // 鍟嗗煄鐨� DIY 缁勪欢锛屽湪 DiyEditor 鐩綍涓� -import { toNumber } from 'lodash-es' - -/** 瑁呬慨妯℃澘琛ㄥ崟 */ -defineOptions({ name: 'DiyTemplateDecorate' }) - -// 宸︿笂瑙掑伐鍏锋爮鎿嶄綔鎸夐挳 -const selectedTemplateItem = ref(0) -const templateItems = reactive([ - { name: '鍩虹璁剧疆', icon: 'ep:iphone' }, - { name: '棣栭〉', icon: 'ep:home-filled' }, - { name: '鎴戠殑', icon: 'ep:user-filled' } -]) - -const message = useMessage() // 娑堟伅寮圭獥 - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>() -const formRef = ref() // 琛ㄥ崟 Ref -// 褰撳墠缂栬緫鐨勫睘鎬� -const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>() -// 鍟嗗煄 H5 棰勮鍦板潃 -const previewUrl = ref('') - -// 鑾峰彇璇︽儏 -const getPageDetail = async (id: any) => { - formLoading.value = true - try { - formData.value = await DiyTemplateApi.getDiyTemplateProperty(id) - currentFormData.value = formData.value - - // 鎷兼帴鎵嬫満棰勮閾炬帴 - const domain = import.meta.env.VITE_MALL_H5_DOMAIN - previewUrl.value = `${domain}/#/pages/index/index?templateId=${formData.value.id}` - } finally { - formLoading.value = false - } -} - -// 妯℃澘缁勪欢搴� -const templateLibs = [] as DiyComponentLibrary[] -// 褰撳墠缁勪欢搴� -const libs = ref<DiyComponentLibrary[]>(templateLibs) -// 妯℃澘閫夐」鍒囨崲 -const handleTemplateItemChange = () => { - // 缂栬緫妯℃澘 - if (selectedTemplateItem.value === 0) { - libs.value = templateLibs - currentFormData.value = formData.value - return - } - - // 缂栬緫椤甸潰 - libs.value = PAGE_LIBS - currentFormData.value = formData.value!.pages.find( - (page: DiyPageApi.DiyPageVO) => page.name === templateItems[selectedTemplateItem.value].name - ) -} - -// 鎻愪氦琛ㄥ崟 -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - if (selectedTemplateItem.value === 0) { - // 鎻愪氦妯℃澘灞炴�� - await DiyTemplateApi.updateDiyTemplateProperty(unref(formData)!) - } else { - // 鎻愪氦椤甸潰灞炴�� - await DiyPageApi.updateDiyPageProperty(unref(currentFormData)!) - } - message.success('淇濆瓨鎴愬姛') - } finally { - formLoading.value = false - } -} - -// 閲嶇疆琛ㄥ崟 -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - used: false, - usedTime: undefined, - remark: '', - previewPicUrls: [], - property: '', - pages: [] - } as DiyTemplateApi.DiyTemplatePropertyVO - formRef.value?.resetFields() -} - -// 閲嶇疆鏃惰褰曞綋鍓嶇紪杈戠殑椤甸潰 -const handleEditorReset = () => storePageIndex() - -//#region 鏃犳劅鍒锋柊 -// 璁板綍鏍囪瘑 -const DIY_PAGE_INDEX_KEY = 'diy_page_index' -// 1. 璁板綍 -const storePageIndex = () => - sessionStorage.setItem(DIY_PAGE_INDEX_KEY, `${selectedTemplateItem.value}`) -// 2. 鎭㈠ -const recoverPageIndex = () => { - // 鎭㈠閲嶇疆鍓嶇殑椤甸潰锛岄粯璁ゆ槸绗竴涓〉闈� - const pageIndex = toNumber(sessionStorage.getItem(DIY_PAGE_INDEX_KEY)) || 0 - // 绉婚櫎鏍囪 - sessionStorage.removeItem(DIY_PAGE_INDEX_KEY) - // 鍒囨崲椤甸潰 - if (pageIndex !== selectedTemplateItem.value) { - selectedTemplateItem.value = pageIndex - handleTemplateItemChange() - } -} -//#endregion - -/** 鍒濆鍖� **/ -const { currentRoute } = useRouter() // 璺敱 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -onMounted(async () => { - resetForm() - if (!currentRoute.value.params.id) { - message.warning('鍙傛暟閿欒锛岄〉闈㈢紪鍙蜂笉鑳戒负绌猴紒') - delView(unref(currentRoute)) - return - } - - // 鏌ヨ璇︽儏 - await getPageDetail(currentRoute.value.params.id) - // 鎭㈠閲嶇疆鍓嶇殑椤甸潰 - recoverPageIndex() -}) -</script> diff --git a/src/views/mall/promotion/diy/template/index.vue b/src/views/mall/promotion/diy/template/index.vue deleted file mode 100644 index 50c5d29..0000000 --- a/src/views/mall/promotion/diy/template/index.vue +++ /dev/null @@ -1,227 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戝晢鍩庤淇�" url="https://doc.iocoder.cn/mall/diy/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="妯℃澘鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユā鏉垮悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:diy-template:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="棰勮鍥�" align="center" prop="previewPicUrls"> - <template #default="scope"> - <el-image - class="h-40px max-w-40px" - v-for="(url, index) in scope.row.previewPicUrls" - :key="index" - :src="url" - :preview-src-list="scope.row.previewPicUrls" - :initial-index="index" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="妯℃澘鍚嶇О" align="center" prop="name" /> - <el-table-column label="鏄惁浣跨敤" align="center" prop="used"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.used" /> - </template> - </el-table-column> - <el-table-column - label="浣跨敤鏃堕棿" - align="center" - prop="usedTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="澶囨敞" align="center" prop="remark" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="200"> - <template #default="scope"> - <el-button - link - type="primary" - @click="handleDecorate(scope.row.id)" - v-hasPermi="['promotion:diy-template:update']" - > - 瑁呬慨 - </el-button> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:diy-template:update']" - > - 缂栬緫 - </el-button> - <template v-if="!scope.row.used"> - <el-button - link - type="primary" - @click="handleUse(scope.row)" - v-hasPermi="['promotion:diy-template:use']" - > - 浣跨敤 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['promotion:diy-template:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <DiyTemplateForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as DiyTemplateApi from '@/api/mall/promotion/diy/template' -import DiyTemplateForm from './DiyTemplateForm.vue' -import { DICT_TYPE } from '@/utils/dict' - -/** 瑁呬慨妯℃澘 */ -defineOptions({ name: 'DiyTemplate' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DiyTemplateApi.getDiyTemplatePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DiyTemplateApi.deleteDiyTemplate(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 浣跨敤妯℃澘 */ -const handleUse = async (row: DiyTemplateApi.DiyTemplateVO) => { - try { - // 浣跨敤妯℃澘鐨勪簩娆$‘璁� - await message.confirm(`鏄惁浣跨敤妯℃澘鈥�${row.name}鈥�?`) - // 鍙戣捣鍒犻櫎 - await DiyTemplateApi.useDiyTemplate(row.id!) - message.success('浣跨敤鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎵撳紑瑁呬慨椤甸潰 */ -const { push } = useRouter() -const handleDecorate = (id: number) => { - push({ name: 'DiyTemplateDecorate', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/kefu/components/KeFuConversationList.vue b/src/views/mall/promotion/kefu/components/KeFuConversationList.vue deleted file mode 100644 index 60188f3..0000000 --- a/src/views/mall/promotion/kefu/components/KeFuConversationList.vue +++ /dev/null @@ -1,236 +0,0 @@ -<template> - <div class="kefu"> - <div - v-for="item in conversationList" - :key="item.id" - :class="{ active: item.id === activeConversationId, pinned: item.adminPinned }" - class="kefu-conversation flex items-center" - @click="openRightMessage(item)" - @contextmenu.prevent="rightClick($event as PointerEvent, item)" - > - <div class="flex justify-center items-center w-100%"> - <div class="flex justify-center items-center w-50px h-50px"> - <!-- 澶村儚 + 鏈 --> - <el-badge - :hidden="item.adminUnreadMessageCount === 0" - :max="99" - :value="item.adminUnreadMessageCount" - > - <el-avatar :src="item.userAvatar" alt="avatar" /> - </el-badge> - </div> - <div class="ml-10px w-100%"> - <div class="flex justify-between items-center w-100%"> - <span class="username">{{ item.userNickname }}</span> - <span class="color-[#989EA6]"> - {{ formatPast(item.lastMessageTime, 'YYYY-mm-dd') }} - </span> - </div> - <!-- 鏈�鍚庤亰澶╁唴瀹� --> - <div - v-dompurify-html=" - getConversationDisplayText(item.lastMessageContentType, item.lastMessageContent) - " - class="last-message flex items-center color-[#989EA6]" - ></div> - </div> - </div> - </div> - - <!-- 鍙抽敭锛岃繘琛屾搷浣滐紙绫讳技寰俊锛� --> - <ul v-show="showRightMenu" :style="rightMenuStyle" class="right-menu-ul"> - <li - v-show="!rightClickConversation.adminPinned" - class="flex items-center" - @click.stop="updateConversationPinned(true)" - > - <Icon class="mr-5px" icon="ep:top" /> - 缃《浼氳瘽 - </li> - <li - v-show="rightClickConversation.adminPinned" - class="flex items-center" - @click.stop="updateConversationPinned(false)" - > - <Icon class="mr-5px" icon="ep:bottom" /> - 鍙栨秷缃《 - </li> - <li class="flex items-center" @click.stop="deleteConversation"> - <Icon class="mr-5px" color="red" icon="ep:delete" /> - 鍒犻櫎浼氳瘽 - </li> - <li class="flex items-center" @click.stop="closeRightMenu"> - <Icon class="mr-5px" color="red" icon="ep:close" /> - 鍙栨秷 - </li> - </ul> - </div> -</template> - -<script lang="ts" setup> -import { KeFuConversationApi, KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import { useEmoji } from './tools/emoji' -import { formatPast } from '@/utils/formatTime' -import { KeFuMessageContentTypeEnum } from './tools/constants' -import { useAppStore } from '@/store/modules/app' - -defineOptions({ name: 'KeFuConversationList' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const appStore = useAppStore() -const { replaceEmoji } = useEmoji() -const conversationList = ref<KeFuConversationRespVO[]>([]) // 浼氳瘽鍒楄〃 -const activeConversationId = ref(-1) // 閫変腑鐨勪細璇� -const collapse = computed(() => appStore.getCollapse) // 鎶樺彔鑿滃崟 - -/** 鍔犺浇浼氳瘽鍒楄〃 */ -const getConversationList = async () => { - const list = await KeFuConversationApi.getConversationList() - list.sort((a: KeFuConversationRespVO, _) => (a.adminPinned ? -1 : 1)) - conversationList.value = list -} -defineExpose({ getConversationList }) - -/** 鎵撳紑鍙充晶鐨勬秷鎭垪琛� */ -const emits = defineEmits<{ - (e: 'change', v: KeFuConversationRespVO): void -}>() -const openRightMessage = (item: KeFuConversationRespVO) => { - activeConversationId.value = item.id - emits('change', item) -} - -/** 鑾峰緱娑堟伅绫诲瀷 */ -const getConversationDisplayText = computed( - () => (lastMessageContentType: number, lastMessageContent: string) => { - switch (lastMessageContentType) { - case KeFuMessageContentTypeEnum.SYSTEM: - return '[绯荤粺娑堟伅]' - case KeFuMessageContentTypeEnum.VIDEO: - return '[瑙嗛娑堟伅]' - case KeFuMessageContentTypeEnum.IMAGE: - return '[鍥剧墖娑堟伅]' - case KeFuMessageContentTypeEnum.PRODUCT: - return '[鍟嗗搧娑堟伅]' - case KeFuMessageContentTypeEnum.ORDER: - return '[璁㈠崟娑堟伅]' - case KeFuMessageContentTypeEnum.VOICE: - return '[璇煶娑堟伅]' - case KeFuMessageContentTypeEnum.TEXT: - return replaceEmoji(lastMessageContent) - default: - return '' - } - } -) - -//======================= 鍙抽敭鑿滃崟 ======================= -const showRightMenu = ref(false) // 鏄剧ず鍙抽敭鑿滃崟 -const rightMenuStyle = ref<any>({}) // 鍙抽敭鑿滃崟 Style -const rightClickConversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 鍙抽敭閫変腑鐨勪細璇濆璞� - -/** 鎵撳紑鍙抽敭鑿滃崟 */ -const rightClick = (mouseEvent: PointerEvent, item: KeFuConversationRespVO) => { - rightClickConversation.value = item - // 鏄剧ず鍙抽敭鑿滃崟 - showRightMenu.value = true - rightMenuStyle.value = { - top: mouseEvent.clientY - 110 + 'px', - left: collapse.value ? mouseEvent.clientX - 80 + 'px' : mouseEvent.clientX - 210 + 'px' - } -} -/** 鍏抽棴鍙抽敭鑿滃崟 */ -const closeRightMenu = () => { - showRightMenu.value = false -} - -/** 缃《浼氳瘽 */ -const updateConversationPinned = async (adminPinned: boolean) => { - // 1. 浼氳瘽缃《/鍙栨秷缃《 - await KeFuConversationApi.updateConversationPinned({ - id: rightClickConversation.value.id, - adminPinned - }) - message.notifySuccess(adminPinned ? '缃《鎴愬姛' : '鍙栨秷缃《鎴愬姛') - // 2. 鍏抽棴鍙抽敭鑿滃崟锛屾洿鏂颁細璇濆垪琛� - closeRightMenu() - await getConversationList() -} - -/** 鍒犻櫎浼氳瘽 */ -const deleteConversation = async () => { - // 1. 鍒犻櫎浼氳瘽 - await message.confirm('鎮ㄧ‘瀹氳鍒犻櫎璇ヤ細璇濆悧锛�') - await KeFuConversationApi.deleteConversation(rightClickConversation.value.id) - // 2. 鍏抽棴鍙抽敭鑿滃崟锛屾洿鏂颁細璇濆垪琛� - closeRightMenu() - await getConversationList() -} - -/** 鐩戝惉鍙抽敭鑿滃崟鐨勬樉绀虹姸鎬侊紝娣诲姞鐐瑰嚮浜嬩欢鐩戝惉鍣� */ -watch(showRightMenu, (val) => { - if (val) { - document.body.addEventListener('click', closeRightMenu) - } else { - document.body.removeEventListener('click', closeRightMenu) - } -}) -</script> - -<style lang="scss" scoped> -.kefu { - &-conversation { - height: 60px; - padding: 10px; - background-color: #fff; - transition: border-left 0.05s ease-in-out; /* 璁剧疆杩囨浮鏁堟灉 */ - - .username { - min-width: 0; - max-width: 60%; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; - } - - .last-message { - width: 200px; - overflow: hidden; // 闅愯棌瓒呭嚭鐨勬枃鏈� - white-space: nowrap; // 绂佹鎹㈣ - text-overflow: ellipsis; // 娣诲姞鐪佺暐鍙� - } - } - - .active { - border-left: 5px #3271ff solid; - background-color: #eff0f1; - } - - .pinned { - background-color: #eff0f1; - } - - .right-menu-ul { - position: absolute; - background-color: #fff; - padding: 10px; - margin: 0; - list-style-type: none; /* 绉婚櫎榛樿鐨勯」鐩鍙� */ - border-radius: 12px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 闃村奖鏁堟灉 */ - width: 130px; - - li { - padding: 8px 16px; - cursor: pointer; - border-radius: 12px; - transition: background-color 0.3s; /* 骞虫粦杩囨浮 */ - &:hover { - background-color: #e0e0e0; /* 鎮仠鏃剁殑鑳屾櫙棰滆壊 */ - } - } - } -} -</style> diff --git a/src/views/mall/promotion/kefu/components/KeFuMessageList.vue b/src/views/mall/promotion/kefu/components/KeFuMessageList.vue deleted file mode 100644 index d3632e6..0000000 --- a/src/views/mall/promotion/kefu/components/KeFuMessageList.vue +++ /dev/null @@ -1,465 +0,0 @@ -<template> - <el-container v-if="showKeFuMessageList" class="kefu"> - <el-header> - <div class="kefu-title">{{ conversation.userNickname }}</div> - </el-header> - <el-main class="kefu-content overflow-visible"> - <el-scrollbar ref="scrollbarRef" always height="calc(100vh - 495px)" @scroll="handleScroll"> - <div v-if="refreshContent" ref="innerRef" class="w-[100%] pb-3px"> - <!-- 娑堟伅鍒楄〃 --> - <div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]"> - <div class="flex justify-center items-center mb-20px"> - <!-- 鏃ユ湡 --> - <div - v-if=" - item.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(item, index) - " - class="date-message" - > - {{ formatDate(item.createTime) }} - </div> - <!-- 绯荤粺娑堟伅 --> - <div - v-if="item.contentType === KeFuMessageContentTypeEnum.SYSTEM" - class="system-message" - > - {{ item.content }} - </div> - </div> - <div - :class="[ - item.senderType === UserTypeEnum.MEMBER - ? `ss-row-left` - : item.senderType === UserTypeEnum.ADMIN - ? `ss-row-right` - : '' - ]" - class="flex mb-20px w-[100%]" - > - <el-avatar - v-if="item.senderType === UserTypeEnum.MEMBER" - :src="conversation.userAvatar" - alt="avatar" - class="w-60px h-60px" - /> - <div - :class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }" - class="p-10px" - > - <!-- 鏂囨湰娑堟伅 --> - <MessageItem :message="item"> - <template v-if="KeFuMessageContentTypeEnum.TEXT === item.contentType"> - <div - v-dompurify-html="replaceEmoji(item.content)" - class="flex items-center" - ></div> - </template> - </MessageItem> - <!-- 鍥剧墖娑堟伅 --> - <MessageItem :message="item"> - <el-image - v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType" - :initial-index="0" - :preview-src-list="[item.content]" - :src="item.content" - class="w-200px" - fit="contain" - preview-teleported - /> - </MessageItem> - <!-- 鍟嗗搧娑堟伅 --> - <MessageItem :message="item"> - <ProductItem - v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType" - :picUrl="getMessageContent(item).picUrl" - :price="getMessageContent(item).price" - :skuText="getMessageContent(item).introduction" - :title="getMessageContent(item).spuName" - :titleWidth="400" - class="max-w-70%" - priceColor="#FF3000" - /> - </MessageItem> - <!-- 璁㈠崟娑堟伅 --> - <MessageItem :message="item"> - <OrderItem - v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType" - :message="item" - class="max-w-70%" - /> - </MessageItem> - </div> - <el-avatar - v-if="item.senderType === UserTypeEnum.ADMIN" - :src="item.senderAvatar" - alt="avatar" - /> - </div> - </div> - </div> - </el-scrollbar> - <div - v-show="showNewMessageTip" - class="newMessageTip flex items-center cursor-pointer" - @click="handleToNewMessage" - > - <span>鏈夋柊娑堟伅</span> - <Icon class="ml-5px" icon="ep:bottom" /> - </div> - </el-main> - <el-footer height="230px"> - <div class="h-[100%]"> - <div class="chat-tools flex items-center"> - <EmojiSelectPopover @select-emoji="handleEmojiSelect" /> - <PictureSelectUpload - class="ml-15px mt-3px cursor-pointer" - @send-picture="handleSendPicture" - /> - </div> - <el-input v-model="message" :rows="6" style="border-style: none" type="textarea" /> - <div class="h-45px flex justify-end"> - <el-button class="mt-10px" type="primary" @click="handleSendMessage">鍙戦��</el-button> - </div> - </div> - </el-footer> - </el-container> - <el-empty v-else description="璇烽�夋嫨宸︿晶鐨勪竴涓細璇濆悗寮�濮�" /> -</template> - -<script lang="ts" setup> -import { ElScrollbar as ElScrollbarType } from 'element-plus' -import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message' -import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import EmojiSelectPopover from './tools/EmojiSelectPopover.vue' -import PictureSelectUpload from './tools/PictureSelectUpload.vue' -import ProductItem from './message/ProductItem.vue' -import OrderItem from './message/OrderItem.vue' -import { Emoji, useEmoji } from './tools/emoji' -import { KeFuMessageContentTypeEnum } from './tools/constants' -import { isEmpty } from '@/utils/is' -import { UserTypeEnum } from '@/utils/constants' -import { formatDate } from '@/utils/formatTime' -import dayjs from 'dayjs' -import relativeTime from 'dayjs/plugin/relativeTime' -import { debounce } from 'lodash-es' -import { jsonParse } from '@/utils' - -dayjs.extend(relativeTime) - -defineOptions({ name: 'KeFuMessageList' }) - -const message = ref('') // 娑堟伅寮圭獥 -const { replaceEmoji } = useEmoji() -const messageTool = useMessage() -const messageList = ref<KeFuMessageRespVO[]>([]) // 娑堟伅鍒楄〃 -const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 鐢ㄦ埛浼氳瘽 -const showNewMessageTip = ref(false) // 鏄剧ず鏈夋柊娑堟伅鎻愮ず -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - conversationId: 0 -}) -const total = ref(0) // 娑堟伅鎬绘潯鏁� -const refreshContent = ref(false) // 鍐呭鍒锋柊,涓昏瑙e喅浼氳瘽娑堟伅椤甸潰楂樺害涓嶄竴鑷村鑷寸殑婊氬姩鍔熻兘绮惧害澶辨晥 - -/** 鑾锋倝娑堟伅鍐呭 */ -const getMessageContent = computed(() => (item: any) => jsonParse(item.content)) -/** 鑾峰緱娑堟伅鍒楄〃 */ -const getMessageList = async () => { - const res = await KeFuMessageApi.getKeFuMessagePage(queryParams) - total.value = res.total - // 鎯呭喌涓�锛氬姞杞芥渶鏂版秷鎭� - if (queryParams.pageNo === 1) { - messageList.value = res.list - } else { - // 鎯呭喌浜岋細鍔犺浇鍘嗗彶娑堟伅 - for (const item of res.list) { - pushMessage(item) - } - } - refreshContent.value = true -} - -/** 娣诲姞娑堟伅 */ -const pushMessage = (message: any) => { - if (messageList.value.some((val) => val.id === message.id)) { - return - } - messageList.value.push(message) -} - -/** 鎸夌収鏃堕棿鍊掑簭锛岃幏鍙栨秷鎭垪琛� */ -const getMessageList0 = computed(() => { - messageList.value.sort((a: any, b: any) => a.createTime - b.createTime) - return messageList.value -}) - -/** 鍒锋柊娑堟伅鍒楄〃 */ -const refreshMessageList = async (message?: any) => { - if (!conversation.value) { - return - } - - if (typeof message !== 'undefined') { - // 褰撳墠鏌ヨ浼氳瘽涓庢秷鎭墍灞炰細璇濅笉涓�鑷村垯涓嶅仛澶勭悊 - if (message.conversationId !== conversation.value.id) { - return - } - pushMessage(message) - } else { - // TODO @puhui999锛氫笉鍩轰簬 page 鍋氥�傝�屾槸娴佸紡鍒嗛〉锛涢�氳繃 createTime 鎺掑簭鏌ヨ锛� - queryParams.pageNo = 1 - await getMessageList() - } - - if (loadHistory.value) { - // 鍙充笅瑙掓樉绀烘湁鏂版秷鎭彁绀� - showNewMessageTip.value = true - } else { - // 婊氬姩鍒版渶鏂版秷鎭 - await handleToNewMessage() - } -} - -/** 鑾峰緱鏂颁細璇濈殑娑堟伅鍒楄〃 */ -// TODO @puhui999锛氬彲浼樺寲锛氬彲浠ヨ�冭檻鏈湴鍋氭瘡涓細璇濈殑娑堟伅 list 缂撳瓨锛涚劧鍚庣偣鍑诲垏鎹㈡椂锛岃鍙栫紦瀛橈紱鐒跺悗寮傛鑾峰彇鏂版秷鎭紝merge 涓嬶紱 -const getNewMessageList = async (val: KeFuConversationRespVO) => { - // 浼氳瘽鍒囨崲,閲嶇疆鐩稿叧鍙傛暟 - queryParams.pageNo = 1 - messageList.value = [] - total.value = 0 - loadHistory.value = false - refreshContent.value = false - // 璁剧疆浼氳瘽鐩稿叧灞炴�� - conversation.value = val - queryParams.conversationId = val.id - // 鑾峰彇娑堟伅 - await refreshMessageList() -} -defineExpose({ getNewMessageList, refreshMessageList }) - -const showKeFuMessageList = computed(() => !isEmpty(conversation.value)) // 鏄惁鏄剧ず鑱婂ぉ鍖哄煙 -const skipGetMessageList = computed(() => { - // 宸插姞杞藉埌鏈�鍚庝竴椤电殑璇濆垯涓嶈Е鍙戞柊鐨勬秷鎭幏鍙� - return total.value > 0 && Math.ceil(total.value / queryParams.pageSize) === queryParams.pageNo -}) // 璺宠繃娑堟伅鑾峰彇 - -/** 澶勭悊琛ㄦ儏閫夋嫨 */ -const handleEmojiSelect = (item: Emoji) => { - message.value += item.name -} - -/** 澶勭悊鍥剧墖鍙戦�� */ -const handleSendPicture = async (picUrl: string) => { - // 缁勭粐鍙戦�佹秷鎭� - const msg = { - conversationId: conversation.value.id, - contentType: KeFuMessageContentTypeEnum.IMAGE, - content: picUrl - } - await sendMessage(msg) -} - -/** 鍙戦�佹枃鏈秷鎭� */ -const handleSendMessage = async () => { - // 1. 鏍¢獙娑堟伅鏄惁涓虹┖ - if (isEmpty(unref(message.value))) { - messageTool.notifyWarning('璇疯緭鍏ユ秷鎭悗鍐嶅彂閫佸摝锛�') - return - } - // 2. 缁勭粐鍙戦�佹秷鎭� - const msg = { - conversationId: conversation.value.id, - contentType: KeFuMessageContentTypeEnum.TEXT, - content: message.value - } - await sendMessage(msg) -} - -/** 鐪熸鍙戦�佹秷鎭� 銆愬叡鐢ㄣ��*/ -const sendMessage = async (msg: any) => { - // 鍙戦�佹秷鎭� - await KeFuMessageApi.sendKeFuMessage(msg) - message.value = '' - // 鍔犺浇娑堟伅鍒楄〃 - await refreshMessageList() -} - -/** 婊氬姩鍒板簳閮� */ -const innerRef = ref<HTMLDivElement>() -const scrollbarRef = ref<InstanceType<typeof ElScrollbarType>>() -const scrollToBottom = async () => { - // 1. 棣栨鍔犺浇鏃舵粴鍔ㄥ埌鏈�鏂版秷鎭紝濡傛灉鍔犺浇鐨勬槸鍘嗗彶娑堟伅鍒欎笉婊氬姩 - if (loadHistory.value) { - return - } - // 2.1 婊氬姩鍒版渶鏂版秷鎭紝鍏抽棴鏂版秷鎭彁绀� - await nextTick() - scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight) - showNewMessageTip.value = false - // 2.2 娑堟伅宸茶 - await KeFuMessageApi.updateKeFuMessageReadStatus(conversation.value.id) -} - -/** 鏌ョ湅鏂版秷鎭� */ -const handleToNewMessage = async () => { - loadHistory.value = false - await scrollToBottom() -} - -const loadHistory = ref(false) // 鍔犺浇鍘嗗彶娑堟伅 -/** 澶勭悊娑堟伅鍒楄〃婊氬姩浜嬩欢(debounce 闄愭祦) */ -const handleScroll = debounce(({ scrollTop }) => { - if (skipGetMessageList.value) { - return - } - // 瑙﹂《鑷姩鍔犺浇涓嬩竴椤垫暟鎹� - if (Math.floor(scrollTop) === 0) { - handleOldMessage() - } - const wrap = scrollbarRef.value?.wrapRef - // 瑙﹀簳閲嶇疆 - if (Math.abs(wrap!.scrollHeight - wrap!.clientHeight - wrap!.scrollTop) < 1) { - loadHistory.value = false - refreshMessageList() - } -}, 200) -/** 鍔犺浇鍘嗗彶娑堟伅 */ -const handleOldMessage = async () => { - // 璁板綍宸叉湁椤甸潰楂樺害 - const oldPageHeight = innerRef.value?.clientHeight - if (!oldPageHeight) { - return - } - loadHistory.value = true - // 鍔犺浇娑堟伅鍒楄〃 - queryParams.pageNo += 1 - await getMessageList() - // 绛夐〉闈㈠姞杞藉畬鍚庯紝鑾峰緱涓婁竴椤垫渶鍚庝竴鏉℃秷鎭殑浣嶇疆锛屾帶鍒舵粴鍔ㄥ埌瀹冩墍鍦ㄤ綅缃� - scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight - oldPageHeight) -} - -/** - * 鏄惁鏄剧ず鏃堕棿 - * - * @param {*} item - 鏁版嵁 - * @param {*} index - 绱㈠紩 - */ -const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => { - if (unref(messageList.value)[index + 1]) { - let dateString = dayjs(unref(messageList.value)[index + 1].createTime).fromNow() - return dateString !== dayjs(unref(item).createTime).fromNow() - } - return false -}) -</script> - -<style lang="scss" scoped> -.kefu { - &-title { - border-bottom: #e4e0e0 solid 1px; - height: 60px; - line-height: 60px; - } - - &-content { - position: relative; - - .newMessageTip { - position: absolute; - bottom: 35px; - right: 35px; - background-color: #fff; - padding: 10px; - border-radius: 30px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 闃村奖鏁堟灉 */ - } - - .ss-row-left { - justify-content: flex-start; - - .kefu-message { - margin-left: 20px; - position: relative; - - &::before { - content: ''; - width: 10px; - height: 10px; - left: -19px; - top: calc(50% - 10px); - position: absolute; - border-left: 5px solid transparent; - border-bottom: 5px solid transparent; - border-top: 5px solid transparent; - border-right: 5px solid #ffffff; - } - } - } - - .ss-row-right { - justify-content: flex-end; - - .kefu-message { - margin-right: 20px; - position: relative; - - &::after { - content: ''; - width: 10px; - height: 10px; - right: -19px; - top: calc(50% - 10px); - position: absolute; - border-left: 5px solid #ffffff; - border-bottom: 5px solid transparent; - border-top: 5px solid transparent; - border-right: 5px solid transparent; - } - } - } - - // 娑堟伅姘旀场 - .kefu-message { - color: #333; - border-radius: 5px; - box-shadow: 3px 5px 15px rgba(0, 0, 0, 0.2); - padding: 5px 10px; - width: auto; - max-width: 50%; - text-align: left; - display: inline-block !important; - position: relative; - word-break: break-all; - background-color: #ffffff; - transition: all 0.2s; - - &:hover { - transform: scale(1.03); - } - } - - .date-message, - .system-message { - width: fit-content; - border-radius: 12rpx; - padding: 8rpx 16rpx; - margin-bottom: 16rpx; - background-color: #e8e8e8; - color: #999; - font-size: 24rpx; - } - } - - .chat-tools { - width: 100%; - border: #e4e0e0 solid 1px; - border-radius: 10px; - height: 44px; - } - - ::v-deep(textarea) { - resize: none; - } -} -</style> diff --git a/src/views/mall/promotion/kefu/components/asserts/a.png b/src/views/mall/promotion/kefu/components/asserts/a.png deleted file mode 100644 index 3293900..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/a.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/aini.png b/src/views/mall/promotion/kefu/components/asserts/aini.png deleted file mode 100644 index 02cf5c4..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/aini.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/aixin.png b/src/views/mall/promotion/kefu/components/asserts/aixin.png deleted file mode 100644 index 25e6422..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/aixin.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/baiyan.png b/src/views/mall/promotion/kefu/components/asserts/baiyan.png deleted file mode 100644 index d16260a..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/baiyan.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/bizui.png b/src/views/mall/promotion/kefu/components/asserts/bizui.png deleted file mode 100644 index a3b1800..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/bizui.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/buhaoyisi.png b/src/views/mall/promotion/kefu/components/asserts/buhaoyisi.png deleted file mode 100644 index 54c4b3f..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/buhaoyisi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/bukesiyi.png b/src/views/mall/promotion/kefu/components/asserts/bukesiyi.png deleted file mode 100644 index 5f272e3..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/bukesiyi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/dajing.png b/src/views/mall/promotion/kefu/components/asserts/dajing.png deleted file mode 100644 index 8649727..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/dajing.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/danao.png b/src/views/mall/promotion/kefu/components/asserts/danao.png deleted file mode 100644 index aa85a29..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/danao.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/daxiao.png b/src/views/mall/promotion/kefu/components/asserts/daxiao.png deleted file mode 100644 index 26206bc..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/daxiao.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/dianzan.png b/src/views/mall/promotion/kefu/components/asserts/dianzan.png deleted file mode 100644 index 2e7f00e..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/dianzan.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/emo.png b/src/views/mall/promotion/kefu/components/asserts/emo.png deleted file mode 100644 index 9c84551..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/emo.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/esi.png b/src/views/mall/promotion/kefu/components/asserts/esi.png deleted file mode 100644 index 84e9726..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/esi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/fadai.png b/src/views/mall/promotion/kefu/components/asserts/fadai.png deleted file mode 100644 index 0772de2..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/fadai.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/fankun.png b/src/views/mall/promotion/kefu/components/asserts/fankun.png deleted file mode 100644 index 6e18dac..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/fankun.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/feiwen.png b/src/views/mall/promotion/kefu/components/asserts/feiwen.png deleted file mode 100644 index be97616..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/feiwen.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/fennu.png b/src/views/mall/promotion/kefu/components/asserts/fennu.png deleted file mode 100644 index 20c5733..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/fennu.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/ganga.png b/src/views/mall/promotion/kefu/components/asserts/ganga.png deleted file mode 100644 index 30ec329..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/ganga.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/ganmao.png b/src/views/mall/promotion/kefu/components/asserts/ganmao.png deleted file mode 100644 index 35bbb89..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/ganmao.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/hanyan.png b/src/views/mall/promotion/kefu/components/asserts/hanyan.png deleted file mode 100644 index a0bc838..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/hanyan.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/haochi.png b/src/views/mall/promotion/kefu/components/asserts/haochi.png deleted file mode 100644 index 2e52b6b..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/haochi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/hongxin.png b/src/views/mall/promotion/kefu/components/asserts/hongxin.png deleted file mode 100644 index 65b5de8..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/hongxin.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/huaixiao.png b/src/views/mall/promotion/kefu/components/asserts/huaixiao.png deleted file mode 100644 index bc0e76c..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/huaixiao.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/jingkong.png b/src/views/mall/promotion/kefu/components/asserts/jingkong.png deleted file mode 100644 index 7aa6584..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/jingkong.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/jingshu.png b/src/views/mall/promotion/kefu/components/asserts/jingshu.png deleted file mode 100644 index 0e984d6..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/jingshu.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/jingya.png b/src/views/mall/promotion/kefu/components/asserts/jingya.png deleted file mode 100644 index 9ba6bab..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/jingya.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/kaixin.png b/src/views/mall/promotion/kefu/components/asserts/kaixin.png deleted file mode 100644 index 29c9f5d..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/kaixin.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/keai.png b/src/views/mall/promotion/kefu/components/asserts/keai.png deleted file mode 100644 index d3b582c..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/keai.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/keshui.png b/src/views/mall/promotion/kefu/components/asserts/keshui.png deleted file mode 100644 index cef489e..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/keshui.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/kun.png b/src/views/mall/promotion/kefu/components/asserts/kun.png deleted file mode 100644 index 1ddc388..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/kun.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/lengku.png b/src/views/mall/promotion/kefu/components/asserts/lengku.png deleted file mode 100644 index c5c6fee..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/lengku.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/liuhan.png b/src/views/mall/promotion/kefu/components/asserts/liuhan.png deleted file mode 100644 index e6ddc6f..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/liuhan.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/liukoushui.png b/src/views/mall/promotion/kefu/components/asserts/liukoushui.png deleted file mode 100644 index 3e2fba6..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/liukoushui.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/liulei.png b/src/views/mall/promotion/kefu/components/asserts/liulei.png deleted file mode 100644 index dbf8204..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/liulei.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/mengbi.png b/src/views/mall/promotion/kefu/components/asserts/mengbi.png deleted file mode 100644 index a4206ee..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/mengbi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/mianwubiaoqing.png b/src/views/mall/promotion/kefu/components/asserts/mianwubiaoqing.png deleted file mode 100644 index 6f315b9..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/mianwubiaoqing.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/nanguo.png b/src/views/mall/promotion/kefu/components/asserts/nanguo.png deleted file mode 100644 index 19b9fb9..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/nanguo.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/outu.png b/src/views/mall/promotion/kefu/components/asserts/outu.png deleted file mode 100644 index 2f9a06d..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/outu.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/picture.svg b/src/views/mall/promotion/kefu/components/asserts/picture.svg deleted file mode 100644 index 8811d49..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/picture.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" - "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg t="1720063872285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6895" - width="200" height="200"> - <path d="M782.16 880.98c-179.31 23.91-361 23.91-540.32 0C138.89 867.25 62 779.43 62 675.57V348.43c0-103.86 76.89-191.69 179.84-205.41 179.31-23.91 361-23.91 540.31 0C885.11 156.75 962 244.57 962 348.43v327.13c0 103.87-76.89 191.69-179.84 205.42z" - fill="#FF554D" p-id="6896"></path> - <path d="M226.11 596.86c-9.74 47.83 17.26 95.6 63.48 111.3C333.49 723.08 394.55 737 469.53 737c59.25 0 105.46-8.69 140.23-19.7 51.59-16.34 79.94-71.16 63.37-122.68-24.47-76.11-65.57-180.7-106.68-180.7-64.62 0-64.62 96.92-64.62 96.92S437.22 317 372.61 317c-82.11 0-117.85 139.12-146.5 279.86z" - fill="#FFFFFF" p-id="6897"></path> - <path d="M782 347m-60 0a60 60 0 1 0 120 0 60 60 0 1 0-120 0Z" fill="#FFBC55" p-id="6898"></path> -</svg> diff --git a/src/views/mall/promotion/kefu/components/asserts/shengqi.png b/src/views/mall/promotion/kefu/components/asserts/shengqi.png deleted file mode 100644 index 7dce41d..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/shengqi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/shuizhuo.png b/src/views/mall/promotion/kefu/components/asserts/shuizhuo.png deleted file mode 100644 index 97d0f0a..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/shuizhuo.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/tianshi.png b/src/views/mall/promotion/kefu/components/asserts/tianshi.png deleted file mode 100644 index eb922dd..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/tianshi.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/xiaodiaoya.png b/src/views/mall/promotion/kefu/components/asserts/xiaodiaoya.png deleted file mode 100644 index 29fbc0e..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/xiaodiaoya.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/xiaoku.png b/src/views/mall/promotion/kefu/components/asserts/xiaoku.png deleted file mode 100644 index 88a169d..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/xiaoku.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/xinsui.png b/src/views/mall/promotion/kefu/components/asserts/xinsui.png deleted file mode 100644 index a0f572a..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/xinsui.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/xiong.png b/src/views/mall/promotion/kefu/components/asserts/xiong.png deleted file mode 100644 index 43dfd70..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/xiong.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/yiwen.png b/src/views/mall/promotion/kefu/components/asserts/yiwen.png deleted file mode 100644 index 4c0da70..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/yiwen.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/yun.png b/src/views/mall/promotion/kefu/components/asserts/yun.png deleted file mode 100644 index 56e5d02..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/yun.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/asserts/ziya.png b/src/views/mall/promotion/kefu/components/asserts/ziya.png deleted file mode 100644 index 593ef5e..0000000 --- a/src/views/mall/promotion/kefu/components/asserts/ziya.png +++ /dev/null Binary files differ diff --git a/src/views/mall/promotion/kefu/components/history/MemberBrowsingHistory.vue b/src/views/mall/promotion/kefu/components/history/MemberBrowsingHistory.vue deleted file mode 100644 index 972760e..0000000 --- a/src/views/mall/promotion/kefu/components/history/MemberBrowsingHistory.vue +++ /dev/null @@ -1,97 +0,0 @@ -<!-- 鐩綍鏄笉鏄彨 member 濂界偣銆傜劧鍚庤繖涓粍浠舵槸 MemberInfo锛岄噷闈㈡湁娴忚瓒宠抗 --> -<template> - <div v-show="!isEmpty(conversation)" class="kefu"> - <div class="header-title h-60px flex justify-center items-center">浠栫殑瓒宠抗</div> - <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> - <el-tab-pane label="鏈�杩戞祻瑙�" name="a" /> - <el-tab-pane label="璁㈠崟鍒楄〃" name="b" /> - </el-tabs> - <div> - <el-scrollbar ref="scrollbarRef" always height="calc(100vh - 400px)" @scroll="handleScroll"> - <!-- 鏈�杩戞祻瑙� --> - <ProductBrowsingHistory v-if="activeName === 'a'" ref="productBrowsingHistoryRef" /> - <!-- 璁㈠崟鍒楄〃 --> - <OrderBrowsingHistory v-if="activeName === 'b'" ref="orderBrowsingHistoryRef" /> - </el-scrollbar> - </div> - </div> - <el-empty v-show="isEmpty(conversation)" description="璇烽�夋嫨宸︿晶鐨勪竴涓細璇濆悗寮�濮�" /> -</template> - -<script lang="ts" setup> -import type { TabsPaneContext } from 'element-plus' -import ProductBrowsingHistory from './ProductBrowsingHistory.vue' -import OrderBrowsingHistory from './OrderBrowsingHistory.vue' -import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import { isEmpty } from '@/utils/is' -import { debounce } from 'lodash-es' -import { ElScrollbar as ElScrollbarType } from 'element-plus/es/components/scrollbar' - -defineOptions({ name: 'MemberBrowsingHistory' }) - -const activeName = ref('a') - -/** tab 鍒囨崲 */ -const productBrowsingHistoryRef = ref<InstanceType<typeof ProductBrowsingHistory>>() -const orderBrowsingHistoryRef = ref<InstanceType<typeof OrderBrowsingHistory>>() -const handleClick = async (tab: TabsPaneContext) => { - activeName.value = tab.paneName as string - await nextTick() - await getHistoryList() -} - -/** 鑾峰緱鍘嗗彶鏁版嵁 */ -// TODO @puhui锛氫笉瑕佺敤 a銆乥 鍝堛�傚氨璁㈠崟鍒楄〃銆佹祻瑙堝垪琛ㄨ繖绉嶅櫠 -const getHistoryList = async () => { - switch (activeName.value) { - case 'a': - await productBrowsingHistoryRef.value?.getHistoryList(conversation.value) - break - case 'b': - await orderBrowsingHistoryRef.value?.getHistoryList(conversation.value) - break - default: - break - } -} - -/** 鍔犺浇涓嬩竴椤垫暟鎹� */ -const loadMore = async () => { - switch (activeName.value) { - case 'a': - await productBrowsingHistoryRef.value?.loadMore() - break - case 'b': - await orderBrowsingHistoryRef.value?.loadMore() - break - default: - break - } -} - -/** 娴忚鍘嗗彶鍒濆鍖� */ -const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 鐢ㄦ埛浼氳瘽 -const initHistory = async (val: KeFuConversationRespVO) => { - activeName.value = 'a' - conversation.value = val - await nextTick() - await getHistoryList() -} -defineExpose({ initHistory }) - -/** 澶勭悊娑堟伅鍒楄〃婊氬姩浜嬩欢(debounce 闄愭祦) */ -const scrollbarRef = ref<InstanceType<typeof ElScrollbarType>>() -const handleScroll = debounce(() => { - const wrap = scrollbarRef.value?.wrapRef - // 瑙﹀簳閲嶇疆 - if (Math.abs(wrap!.scrollHeight - wrap!.clientHeight - wrap!.scrollTop) < 1) { - loadMore() - } -}, 200) -</script> - -<style lang="scss" scoped> -.header-title { - border-bottom: #e4e0e0 solid 1px; -} -</style> diff --git a/src/views/mall/promotion/kefu/components/history/OrderBrowsingHistory.vue b/src/views/mall/promotion/kefu/components/history/OrderBrowsingHistory.vue deleted file mode 100644 index 8fb8891..0000000 --- a/src/views/mall/promotion/kefu/components/history/OrderBrowsingHistory.vue +++ /dev/null @@ -1,44 +0,0 @@ -<template> - <OrderItem v-for="item in list" :key="item.id" :order="item" class="mb-10px" /> -</template> - -<script lang="ts" setup> -import OrderItem from '@/views/mall/promotion/kefu/components/message/OrderItem.vue' -import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import { getOrderPage } from '@/api/mall/trade/order' -import { concat } from 'lodash-es' - -defineOptions({ name: 'OrderBrowsingHistory' }) - -const list = ref<any>([]) // 鍒楄〃 -const total = ref(0) // 鎬绘暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: 0 -}) -const skipGetMessageList = computed(() => { - // 宸插姞杞藉埌鏈�鍚庝竴椤电殑璇濆垯涓嶈Е鍙戞柊鐨勬秷鎭幏鍙� - return total.value > 0 && Math.ceil(total.value / queryParams.pageSize) === queryParams.pageNo -}) // 璺宠繃娑堟伅鑾峰彇 - -/** 鑾峰緱娴忚璁板綍 */ -const getHistoryList = async (val: KeFuConversationRespVO) => { - queryParams.userId = val.userId - const res = await getOrderPage(queryParams) - total.value = res.total - list.value = res.list -} - -/** 鍔犺浇涓嬩竴椤垫暟鎹� */ -const loadMore = async () => { - if (skipGetMessageList.value) { - return - } - queryParams.pageNo += 1 - const res = await getOrderPage(queryParams) - total.value = res.total - concat(list.value, res.list) -} -defineExpose({ getHistoryList, loadMore }) -</script> diff --git a/src/views/mall/promotion/kefu/components/history/ProductBrowsingHistory.vue b/src/views/mall/promotion/kefu/components/history/ProductBrowsingHistory.vue deleted file mode 100644 index c9bff18..0000000 --- a/src/views/mall/promotion/kefu/components/history/ProductBrowsingHistory.vue +++ /dev/null @@ -1,57 +0,0 @@ -<template> - <ProductItem - v-for="item in list" - :key="item.id" - :picUrl="item.picUrl" - :price="item.price" - :skuText="item.introduction" - :title="item.spuName" - :titleWidth="400" - class="mb-10px" - priceColor="#FF3000" - /> -</template> - -<script lang="ts" setup> -import { getBrowseHistoryPage } from '@/api/mall/product/history' -import ProductItem from '@/views/mall/promotion/kefu/components/message/ProductItem.vue' -import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import { concat } from 'lodash-es' - -defineOptions({ name: 'ProductBrowsingHistory' }) - -const list = ref<any>([]) // 鍒楄〃 -const total = ref(0) // 鎬绘暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: 0, - userDeleted: false -}) -const skipGetMessageList = computed(() => { - // 宸插姞杞藉埌鏈�鍚庝竴椤电殑璇濆垯涓嶈Е鍙戞柊鐨勬秷鎭幏鍙� - return total.value > 0 && Math.ceil(total.value / queryParams.pageSize) === queryParams.pageNo -}) // 璺宠繃娑堟伅鑾峰彇 - -/** 鑾峰緱娴忚璁板綍 */ -const getHistoryList = async (val: KeFuConversationRespVO) => { - queryParams.userId = val.userId - const res = await getBrowseHistoryPage(queryParams) - total.value = res.total - list.value = res.list -} - -/** 鍔犺浇涓嬩竴椤垫暟鎹� */ -const loadMore = async () => { - if (skipGetMessageList.value) { - return - } - queryParams.pageNo += 1 - const res = await getBrowseHistoryPage(queryParams) - total.value = res.total - concat(list.value, res.list) -} -defineExpose({ getHistoryList, loadMore }) -</script> - -<style lang="scss" scoped></style> diff --git a/src/views/mall/promotion/kefu/components/index.ts b/src/views/mall/promotion/kefu/components/index.ts deleted file mode 100644 index 585d0da..0000000 --- a/src/views/mall/promotion/kefu/components/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import KeFuConversationList from './KeFuConversationList.vue' -import KeFuMessageList from './KeFuMessageList.vue' -import MemberBrowsingHistory from './history/MemberBrowsingHistory.vue' - -export { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } diff --git a/src/views/mall/promotion/kefu/components/message/MessageItem.vue b/src/views/mall/promotion/kefu/components/message/MessageItem.vue deleted file mode 100644 index 325a363..0000000 --- a/src/views/mall/promotion/kefu/components/message/MessageItem.vue +++ /dev/null @@ -1,24 +0,0 @@ -<template> - <!-- 娑堟伅缁勪欢 --> - <div - :class="[ - message.senderType === UserTypeEnum.MEMBER - ? `ml-10px` - : message.senderType === UserTypeEnum.ADMIN - ? `mr-10px` - : '' - ]" - > - <slot></slot> - </div> -</template> - -<script lang="ts" setup> -import { UserTypeEnum } from '@/utils/constants' -import { KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message' - -defineOptions({ name: 'MessageItem' }) -defineProps<{ - message: KeFuMessageRespVO -}>() -</script> diff --git a/src/views/mall/promotion/kefu/components/message/OrderItem.vue b/src/views/mall/promotion/kefu/components/message/OrderItem.vue deleted file mode 100644 index 5ee21f2..0000000 --- a/src/views/mall/promotion/kefu/components/message/OrderItem.vue +++ /dev/null @@ -1,146 +0,0 @@ -<template> - <div v-if="isObject(getMessageContent)"> - <div :key="getMessageContent.id" class="order-list-card-box mt-14px"> - <div class="order-card-header flex items-center justify-between p-x-20px"> - <div class="order-no">璁㈠崟鍙凤細{{ getMessageContent.no }}</div> - <div :class="formatOrderColor(getMessageContent)" class="order-state font-16"> - {{ formatOrderStatus(getMessageContent) }} - </div> - </div> - <div v-for="item in getMessageContent.items" :key="item.id" class="border-bottom"> - <ProductItem - :num="item.count" - :picUrl="item.picUrl" - :price="item.price" - :skuText="item.properties.map((property: any) => property.valueName).join(' ')" - :title="item.spuName" - /> - </div> - <div class="pay-box flex justify-end pr-20px"> - <div class="flex items-center"> - <div class="discounts-title pay-color" - >鍏� {{ getMessageContent?.productCount }} 浠跺晢鍝�,鎬婚噾棰�: - </div> - <div class="discounts-money pay-color"> - 锟{ fenToYuan(getMessageContent?.payPrice) }} - </div> - </div> - </div> - </div> - </div> -</template> - -<script lang="ts" setup> -import { fenToYuan, jsonParse } from '@/utils' -import { KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message' -import { isObject } from '@/utils/is' -import ProductItem from '@/views/mall/promotion/kefu/components/message/ProductItem.vue' - -defineOptions({ name: 'OrderItem' }) -const props = defineProps<{ - message?: KeFuMessageRespVO - order?: any -}>() - -const getMessageContent = computed(() => - typeof props.message !== 'undefined' ? jsonParse(props!.message!.content) : props.order -) - -/** - * 鏍煎紡鍖栬鍗曠姸鎬佺殑棰滆壊 - * - * @param order 璁㈠崟 - * @return {string} 棰滆壊鐨� class 鍚嶇О - */ -function formatOrderColor(order: any) { - if (order.status === 0) { - return 'info-color' - } - if (order.status === 10 || order.status === 20 || (order.status === 30 && !order.commentStatus)) { - return 'warning-color' - } - if (order.status === 30 && order.commentStatus) { - return 'success-color' - } - return 'danger-color' -} - -/** - * 鏍煎紡鍖栬鍗曠姸鎬� - * - * @param order 璁㈠崟 - */ -function formatOrderStatus(order: any) { - if (order.status === 0) { - return '寰呬粯娆�' - } - if (order.status === 10 && order.deliveryType === 1) { - return '寰呭彂璐�' - } - if (order.status === 10 && order.deliveryType === 2) { - return '寰呮牳閿�' - } - if (order.status === 20) { - return '寰呮敹璐�' - } - if (order.status === 30 && !order.commentStatus) { - return '寰呰瘎浠�' - } - if (order.status === 30 && order.commentStatus) { - return '宸插畬鎴�' - } - return '宸插叧闂�' -} -</script> - -<style lang="scss" scoped> -.order-list-card-box { - border-radius: 10px; - padding: 10px; - background-color: #e2e2e2; - - .order-card-header { - height: 28px; - - .order-no { - font-size: 16px; - font-weight: 500; - } - } - - .pay-box { - .discounts-title { - font-size: 16px; - line-height: normal; - color: #999999; - } - - .discounts-money { - font-size: 16px; - line-height: normal; - color: #999; - font-family: OPPOSANS; - } - - .pay-color { - color: #333; - } - } -} - -.warning-color { - color: #faad14; -} - -.danger-color { - color: #ff3000; -} - -.success-color { - color: #52c41a; -} - -.info-color { - color: #999999; -} -</style> diff --git a/src/views/mall/promotion/kefu/components/message/ProductItem.vue b/src/views/mall/promotion/kefu/components/message/ProductItem.vue deleted file mode 100644 index ba2a2a9..0000000 --- a/src/views/mall/promotion/kefu/components/message/ProductItem.vue +++ /dev/null @@ -1,189 +0,0 @@ -<template> - <div> - <div> - <slot name="top"></slot> - </div> - <div - :style="[{ borderRadius: radius + 'px', marginBottom: marginBottom + 'px' }]" - class="ss-order-card-warp flex items-stretch justify-between bg-white" - > - <div class="img-box mr-24px"> - <el-image - :initial-index="0" - :preview-src-list="[picUrl]" - :src="picUrl" - class="order-img" - fit="contain" - preview-teleported - /> - </div> - <div - :style="[{ width: titleWidth ? titleWidth + 'px' : '' }]" - class="box-right flex flex-col justify-between" - > - <div v-if="title" class="title-text ss-line-2">{{ title }}</div> - <div v-if="skuString" class="spec-text mt-8px mb-12px">{{ skuString }}</div> - <div class="groupon-box"> - <slot name="groupon"></slot> - </div> - <div class="flex"> - <div class="flex items-center"> - <div - v-if="price && Number(price) > 0" - :style="[{ color: priceColor }]" - class="price-text flex items-center" - > - 锟{ fenToYuan(price) }} - </div> - <div v-if="num" class="total-text flex items-center">x {{ num }}</div> - <slot name="priceSuffix"></slot> - </div> - </div> - <div class="tool-box"> - <slot name="tool"></slot> - </div> - <div> - <slot name="rightBottom"></slot> - </div> - </div> - </div> - </div> -</template> - -<script lang="ts" setup> -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'ProductItem' }) -const props = defineProps({ - picUrl: { - type: String, - default: 'https://img1.baidu.com/it/u=1601695551,235775011&fm=26&fmt=auto' - }, - title: { - type: String, - default: '' - }, - titleWidth: { - type: Number, - default: 0 - }, - skuText: { - type: [String, Array], - default: '' - }, - price: { - type: [String, Number], - default: '' - }, - priceColor: { - type: [String], - default: '' - }, - num: { - type: [String, Number], - default: 0 - }, - score: { - type: [String, Number], - default: '' - }, - radius: { - type: [String], - default: '' - }, - marginBottom: { - type: [String], - default: '' - } -}) - -/** SKU 灞曠ず瀛楃涓� */ -const skuString = computed(() => { - if (!props.skuText) { - return '' - } - if (typeof props.skuText === 'object') { - return props.skuText.join(',') - } - return props.skuText -}) -</script> - -<style lang="scss" scoped> -.ss-order-card-warp { - padding: 20px; - border-radius: 10px; - background-color: #e2e2e2; - - .img-box { - width: 80px; - height: 80px; - border-radius: 10px; - overflow: hidden; - - .order-img { - width: 80px; - height: 80px; - } - } - - .box-right { - flex: 1; - position: relative; - - .tool-box { - position: absolute; - right: 0px; - bottom: -10px; - } - } - - .title-text { - font-size: 16px; - font-weight: 500; - line-height: 20px; - } - - .spec-text { - font-size: 16px; - font-weight: 400; - color: #999999; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 1; - -webkit-box-orient: vertical; - } - - .price-text { - font-size: 16px; - font-weight: 500; - font-family: OPPOSANS; - } - - .total-text { - font-size: 16px; - font-weight: 400; - line-height: 16px; - color: #999999; - margin-left: 8px; - } -} - -.ss-line { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-box-orient: vertical; - - &-1 { - -webkit-line-clamp: 1; - } - - &-2 { - -webkit-line-clamp: 2; - } -} -</style> diff --git a/src/views/mall/promotion/kefu/components/tools/EmojiSelectPopover.vue b/src/views/mall/promotion/kefu/components/tools/EmojiSelectPopover.vue deleted file mode 100644 index 43c096d..0000000 --- a/src/views/mall/promotion/kefu/components/tools/EmojiSelectPopover.vue +++ /dev/null @@ -1,42 +0,0 @@ -<!-- emoji 琛ㄦ儏閫夋嫨缁勪欢 --> -<template> - <el-popover :width="500" placement="top" trigger="click"> - <template #reference> - <Icon :size="30" class="ml-10px cursor-pointer" icon="twemoji:grinning-face" /> - </template> - <ElScrollbar height="300px"> - <ul class="ml-2 flex flex-wrap px-2"> - <li - v-for="(item, index) in emojiList" - :key="index" - :style="{ - borderColor: 'var(--el-color-primary)', - color: 'var(--el-color-primary)' - }" - :title="item.name" - class="icon-item mr-2 mt-1 w-1/10 flex cursor-pointer items-center justify-center border border-solid p-2" - @click="handleSelect(item)" - > - <img :src="item.url" class="w-24px h-24px" /> - </li> - </ul> - </ElScrollbar> - </el-popover> -</template> - -<script lang="ts" setup> -defineOptions({ name: 'EmojiSelectPopover' }) -import { Emoji, useEmoji } from './emoji' - -const { getEmojiList } = useEmoji() -const emojiList = computed(() => getEmojiList()) - -/** 閫夋嫨 emoji 琛ㄦ儏 */ -const emits = defineEmits<{ - (e: 'select-emoji', v: Emoji) -}>() -const handleSelect = (item: Emoji) => { - // 鏁翠釜 emoji 鏁版嵁浼犻�掑嚭鍘伙紝鏂逛究浠ュ悗杈撳叆妗嗙洿鎺ユ樉绀鸿〃鎯� - emits('select-emoji', item) -} -</script> diff --git a/src/views/mall/promotion/kefu/components/tools/PictureSelectUpload.vue b/src/views/mall/promotion/kefu/components/tools/PictureSelectUpload.vue deleted file mode 100644 index 9742353..0000000 --- a/src/views/mall/promotion/kefu/components/tools/PictureSelectUpload.vue +++ /dev/null @@ -1,93 +0,0 @@ -<!-- 鍥剧墖閫夋嫨 --> -<template> - <div> - <img :src="Picture" class="w-35px h-35px" @click="selectAndUpload" /> - </div> -</template> - -<script lang="ts" setup> -import Picture from '@/views/mall/promotion/kefu/components/asserts/picture.svg' -import * as FileApi from '@/api/infra/file' - -defineOptions({ name: 'PictureSelectUpload' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -/** 閫夋嫨骞朵笂浼犳枃浠� */ -const emits = defineEmits<{ - (e: 'send-picture', v: string): void -}>() -const selectAndUpload = async () => { - const files: any = await getFiles() - message.success('鍥剧墖鍙戦�佷腑璇风◢绛夈�傘�傘��') - const res = await FileApi.updateFile({ file: files[0].file }) - emits('send-picture', res.data) -} - -/** - * 鍞よ捣鏂囦欢閫夋嫨绐楀彛锛屽苟鑾峰彇閫夋嫨鐨勬枃浠� - * - * @param {Object} options - 閰嶇疆閫夐」 - * @param {boolean} [options.multiple=true] - 鏄惁鏀寔澶氶�� - * @param {string} [options.accept=''] - 鏂囦欢涓婁紶鏍煎紡闄愬埗 - * @param {number} [options.limit=1] - 鍗曟涓婁紶鏈�澶ф枃浠舵暟 - * @param {number} [options.fileSize=500] - 鍗曚釜鏂囦欢澶у皬闄愬埗锛堝崟浣嶏細MB锛� - * @returns {Promise<Array>} 閫夋嫨鐨勬枃浠跺垪琛紝姣忎釜鏂囦欢甯︽湁涓�涓猽id - */ -async function getFiles(options = {}) { - const { multiple, accept, limit, fileSize } = { - multiple: true, - accept: 'image/jpeg, image/png, image/gif', // 榛樿閫夋嫨鍥剧墖 - limit: 1, - fileSize: 500, - ...options - } - - // 鍒涘缓鏂囦欢閫夋嫨鍏冪礌 - const input = document.createElement('input') - input.type = 'file' - input.style.display = 'none' - if (multiple) input.multiple = true - if (accept) input.accept = accept - - // 灏嗘枃浠堕�夋嫨鍏冪礌娣诲姞鍒版枃妗d腑 - document.body.appendChild(input) - - // 瑙﹀彂鏂囦欢閫夋嫨鍏冪礌鐨勭偣鍑讳簨浠� - input.click() - - // 绛夊緟鏂囦欢閫夋嫨鍏冪礌鐨� change 浜嬩欢 - try { - return await new Promise((resolve, reject) => { - input.addEventListener('change', (event: any) => { - const filesArray = Array.from(event?.target?.files || []) - - // 浠庢枃妗d腑绉婚櫎鏂囦欢閫夋嫨鍏冪礌 - document.body.removeChild(input) - - // 鍒ゆ柇鏄惁瓒呭嚭涓婁紶鏁伴噺闄愬埗 - if (filesArray.length > limit) { - reject({ errorType: 'limit', files: filesArray }) - return - } - - // 鍒ゆ柇鏄惁瓒呭嚭涓婁紶鏂囦欢澶у皬闄愬埗 - const overSizedFiles = filesArray.filter((file: File) => file.size / 1024 ** 2 > fileSize) - if (overSizedFiles.length > 0) { - reject({ errorType: 'fileSize', files: overSizedFiles }) - return - } - - // 鐢熸垚鏂囦欢鍒楄〃锛屽苟娣诲姞 uid - const fileList = filesArray.map((file, index) => ({ file, uid: Date.now() + index })) - resolve(fileList) - }) - }) - } catch (error) { - console.error('閫夋嫨鏂囦欢鍑洪敊:', error) - throw error - } -} -</script> - -<style lang="scss" scoped></style> diff --git a/src/views/mall/promotion/kefu/components/tools/constants.ts b/src/views/mall/promotion/kefu/components/tools/constants.ts deleted file mode 100644 index 750e7f5..0000000 --- a/src/views/mall/promotion/kefu/components/tools/constants.ts +++ /dev/null @@ -1,17 +0,0 @@ -// 瀹㈡湇娑堟伅绫诲瀷鏋氫妇绫� -export const KeFuMessageContentTypeEnum = { - TEXT: 1, // 鏂囨湰娑堟伅 - IMAGE: 2, // 鍥剧墖娑堟伅 - VOICE: 3, // 璇煶娑堟伅 - VIDEO: 4, // 瑙嗛娑堟伅 - SYSTEM: 5, // 绯荤粺娑堟伅 - // ========== 鍟嗗煄鐗规畩娑堟伅 ========== - PRODUCT: 10, // 鍟嗗搧娑堟伅 - ORDER: 11 // 璁㈠崟娑堟伅" -} - -// Promotion 鐨� WebSocket 娑堟伅绫诲瀷鏋氫妇绫� -export const WebSocketMessageTypeConstants = { - KEFU_MESSAGE_TYPE: 'kefu_message_type', // 瀹㈡湇娑堟伅绫诲瀷 - KEFU_MESSAGE_ADMIN_READ: 'kefu_message_read_status_change' // 瀹㈡湇娑堟伅绠$悊鍛樺凡璇� -} diff --git a/src/views/mall/promotion/kefu/components/tools/emoji.ts b/src/views/mall/promotion/kefu/components/tools/emoji.ts deleted file mode 100644 index 7e3f19b..0000000 --- a/src/views/mall/promotion/kefu/components/tools/emoji.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { isEmpty } from '@/utils/is' - -const emojiList = [ - { name: '[绗戞帀鐗橾', file: 'xiaodiaoya.png' }, - { name: '[鍙埍]', file: 'keai.png' }, - { name: '[鍐烽叿]', file: 'lengku.png' }, - { name: '[闂槾]', file: 'bizui.png' }, - { name: '[鐢熸皵]', file: 'shengqi.png' }, - { name: '[鎯婃亹]', file: 'jingkong.png' }, - { name: '[鐬岀潯]', file: 'keshui.png' }, - { name: '[澶х瑧]', file: 'daxiao.png' }, - { name: '[鐖卞績]', file: 'aixin.png' }, - { name: '[鍧忕瑧]', file: 'huaixiao.png' }, - { name: '[椋炲惢]', file: 'feiwen.png' }, - { name: '[鐤戦棶]', file: 'yiwen.png' }, - { name: '[寮�蹇僝', file: 'kaixin.png' }, - { name: '[鍙戝憜]', file: 'fadai.png' }, - { name: '[娴佹唱]', file: 'liulei.png' }, - { name: '[姹楅]', file: 'hanyan.png' }, - { name: '[鎯婃倸]', file: 'jingshu.png' }, - { name: '[鍥皛]', file: 'kun.png' }, - { name: '[蹇冪]', file: 'xinsui.png' }, - { name: '[澶╀娇]', file: 'tianshi.png' }, - { name: '[鏅昡', file: 'yun.png' }, - { name: '[鍟奭', file: 'a.png' }, - { name: '[鎰ゆ�抅', file: 'fennu.png' }, - { name: '[鐫$潃]', file: 'shuizhuo.png' }, - { name: '[闈㈡棤琛ㄦ儏]', file: 'mianwubiaoqing.png' }, - { name: '[闅捐繃]', file: 'nanguo.png' }, - { name: '[鐘洶]', file: 'fankun.png' }, - { name: '[濂藉悆]', file: 'haochi.png' }, - { name: '[鍛曞悙]', file: 'outu.png' }, - { name: '[榫囩墮]', file: 'ziya.png' }, - { name: '[鎳垫瘮]', file: 'mengbi.png' }, - { name: '[鐧界溂]', file: 'baiyan.png' }, - { name: '[楗挎]', file: 'esi.png' }, - { name: '[鍑禲', file: 'xiong.png' }, - { name: '[鎰熷啋]', file: 'ganmao.png' }, - { name: '[娴佹睏]', file: 'liuhan.png' }, - { name: '[绗戝摥]', file: 'xiaoku.png' }, - { name: '[娴佸彛姘碷', file: 'liukoushui.png' }, - { name: '[灏村艾]', file: 'ganga.png' }, - { name: '[鎯婅]', file: 'jingya.png' }, - { name: '[澶ф儕]', file: 'dajing.png' }, - { name: '[涓嶅ソ鎰忔�漖', file: 'buhaoyisi.png' }, - { name: '[澶ч椆]', file: 'danao.png' }, - { name: '[涓嶅彲鎬濊]', file: 'bukesiyi.png' }, - { name: '[鐖变綘]', file: 'aini.png' }, - { name: '[绾㈠績]', file: 'hongxin.png' }, - { name: '[鐐硅禐]', file: 'dianzan.png' }, - { name: '[鎭堕瓟]', file: 'emo.png' } -] - -export interface Emoji { - name: string - url: string -} - -export const useEmoji = () => { - const emojiPathList = ref<any[]>([]) - - /** 鍔犺浇鏈湴鍥剧墖 */ - const initStaticEmoji = async () => { - const pathList = import.meta.glob( - '@/views/mall/promotion/kefu/components/asserts/*.{png,jpg,jpeg,svg}' - ) - for (const path in pathList) { - const imageModule: any = await pathList[path]() - emojiPathList.value.push(imageModule.default) - } - } - - /** 鍒濆鍖� */ - onMounted(async () => { - if (isEmpty(emojiPathList.value)) { - await initStaticEmoji() - } - }) - - /** - * 灏嗘枃鏈腑鐨勮〃鎯呮浛鎹㈡垚鍥剧墖 - * - * @param data 鏂囨湰 - * @return 鏇挎崲鍚庣殑鏂囨湰 - */ - const replaceEmoji = (content: string) => { - let newData = content - if (typeof newData !== 'object') { - const reg = /\[(.+?)]/g // [] 涓嫭鍙� - const zhEmojiName = newData.match(reg) - if (zhEmojiName) { - zhEmojiName.forEach((item) => { - const emojiFile = getEmojiFileByName(item) - newData = newData.replace( - item, - `<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${emojiFile}"/>` - ) - }) - } - } - return newData - } - - /** - * 鑾峰緱鎵�鏈夎〃鎯� - * - * @return 琛ㄦ儏鍒楄〃 - */ - function getEmojiList(): Emoji[] { - return emojiList.map((item) => ({ - url: getEmojiFileByName(item.name), - name: item.name - })) as Emoji[] - } - - function getEmojiFileByName(name: string) { - for (const emoji of emojiList) { - if (emoji.name === name) { - return emojiPathList.value.find((item: string) => item.indexOf(emoji.file) > -1) - } - } - return false - } - - return { replaceEmoji, getEmojiList } -} diff --git a/src/views/mall/promotion/kefu/index.vue b/src/views/mall/promotion/kefu/index.vue deleted file mode 100644 index e6b4976..0000000 --- a/src/views/mall/promotion/kefu/index.vue +++ /dev/null @@ -1,137 +0,0 @@ -<template> - <el-row :gutter="10"> - <!-- 浼氳瘽鍒楄〃 --> - <el-col :span="6"> - <ContentWrap> - <KeFuConversationList ref="keFuConversationRef" @change="handleChange" /> - </ContentWrap> - </el-col> - <!-- 浼氳瘽璇︽儏锛堥�変腑浼氳瘽鐨勬秷鎭垪琛級 --> - <el-col :span="12"> - <ContentWrap> - <KeFuMessageList ref="keFuChatBoxRef" @change="getConversationList" /> - </ContentWrap> - </el-col> - <!-- 浼氬憳瓒宠抗锛堥�変腑浼氳瘽鐨勪細鍛樿冻杩癸級 --> - <el-col :span="6"> - <ContentWrap> - <MemberBrowsingHistory ref="memberBrowsingHistoryRef" /> - </ContentWrap> - </el-col> - </el-row> -</template> - -<script lang="ts" setup> -import { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } from './components' -import { WebSocketMessageTypeConstants } from './components/tools/constants' -import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' -import { getAccessToken } from '@/utils/auth' -import { useWebSocket } from '@vueuse/core' - -defineOptions({ name: 'KeFu' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -// ======================= WebSocket start ======================= -const server = ref( - (import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') + '?token=' + getAccessToken() -) // WebSocket 鏈嶅姟鍦板潃 - -/** 鍙戣捣 WebSocket 杩炴帴 */ -const { data, close, open } = useWebSocket(server.value, { - autoReconnect: true, - heartbeat: true -}) - -/** 鐩戝惉 WebSocket 鏁版嵁 */ -watchEffect(() => { - if (!data.value) { - return - } - try { - // 1. 鏀跺埌蹇冭烦 - if (data.value === 'pong') { - return - } - - // 2.1 瑙f瀽 type 娑堟伅绫诲瀷 - const jsonMessage = JSON.parse(data.value) - const type = jsonMessage.type - if (!type) { - message.error('鏈煡鐨勬秷鎭被鍨嬶細' + data.value) - return - } - // 2.2 娑堟伅绫诲瀷锛欿EFU_MESSAGE_TYPE - if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) { - // 鍒锋柊浼氳瘽鍒楄〃 - // TODO @puhui999锛氫笉搴旇鍒锋柊鍒楄〃锛岃�屾槸鏍规嵁娑堟伅锛屾湰鍦� update 鍒楄〃鐨勬暟鎹紱 - getConversationList() - // 鍒锋柊娑堟伅鍒楄〃 - keFuChatBoxRef.value?.refreshMessageList(JSON.parse(jsonMessage.content)) - return - } - // 2.3 娑堟伅绫诲瀷锛欿EFU_MESSAGE_ADMIN_READ - if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_ADMIN_READ) { - // 鍒锋柊浼氳瘽鍒楄〃 - // TODO @puhui999锛氫笉搴旇鍒锋柊鍒楄〃锛岃�屾槸鏍规嵁娑堟伅锛屾湰鍦� update 鍒楄〃鐨勬暟鎹紱 - getConversationList() - } - } catch (error) { - console.error(error) - } -}) -// ======================= WebSocket end ======================= -/** 鍔犺浇浼氳瘽鍒楄〃 */ -const keFuConversationRef = ref<InstanceType<typeof KeFuConversationList>>() -const getConversationList = () => { - keFuConversationRef.value?.getConversationList() -} - -/** 鍔犺浇鎸囧畾浼氳瘽鐨勬秷鎭垪琛� */ -const keFuChatBoxRef = ref<InstanceType<typeof KeFuMessageList>>() -const memberBrowsingHistoryRef = ref<InstanceType<typeof MemberBrowsingHistory>>() -const handleChange = (conversation: KeFuConversationRespVO) => { - keFuChatBoxRef.value?.getNewMessageList(conversation) - memberBrowsingHistoryRef.value?.initHistory(conversation) -} - -/** 鍒濆鍖� */ -onMounted(() => { - getConversationList() - // 鎵撳紑 websocket 杩炴帴 - open() -}) - -/** 閿�姣� */ -onBeforeUnmount(() => { - // 鍏抽棴 websocket 杩炴帴 - close() -}) -</script> - -<style lang="scss"> -.kefu { - height: calc(100vh - 165px); - overflow: auto; /* 纭繚鍐呭鍙粴鍔� */ -} - -/* 瀹氫箟婊氬姩鏉℃牱寮� */ -::-webkit-scrollbar { - width: 10px; - height: 6px; -} - -/* 瀹氫箟婊氬姩鏉¤建閬� 鍐呴槾褰�+鍦嗚 */ -::-webkit-scrollbar-track { - box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5); - border-radius: 10px; - background-color: #fff; -} - -/* 瀹氫箟婊戝潡 鍐呴槾褰�+鍦嗚 */ -::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5); - background-color: rgba(240, 240, 240, 0.5); -} -</style> diff --git a/src/views/mall/promotion/rewardActivity/RewardForm.vue b/src/views/mall/promotion/rewardActivity/RewardForm.vue deleted file mode 100644 index 9fb69a5..0000000 --- a/src/views/mall/promotion/rewardActivity/RewardForm.vue +++ /dev/null @@ -1,325 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="80px" - v-loading="formLoading" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" /> - </el-form-item> - <el-form-item label="娲诲姩鏃堕棿" prop="startAndEndTime"> - <el-date-picker - v-model="formData.startAndEndTime" - type="datetimerange" - range-separator="-" - :start-placeholder="t('common.startTimeText')" - :end-placeholder="t('common.endTimeText')" - /> - </el-form-item> - <el-form-item label="鏉′欢绫诲瀷" prop="conditionType"> - <el-radio-group v-model="formData.conditionType"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_CONDITION_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="浼樻儬璁剧疆"> - <template v-for="(item, index) in formData.rules" :key="index"> - <el-row type="flex"> - <el-col :span="24" style="font-weight: bold; display: flex"> - 娲诲姩灞傜骇{{ index + 1 }} - <el-button - link - type="danger" - style="margin-left: auto" - v-if="index != 0" - @click="deleteActivityRule(index)" - > - 鍒犻櫎 - </el-button> - </el-col> - <e-form :ref="'formRef' + index" :model="item"> - <el-form-item - label="浼樻儬闂ㄦ:" - prop="limit" - label-width="100px" - style="padding-left: 50px" - > - 婊� - <el-input - style="width: 150px; padding: 0 10px" - v-model="item.limit" - type="number" - placeholder="" - /> - 鍏� - </el-form-item> - <el-form-item label="浼樻儬鍐呭:" label-width="100px" style="padding-left: 50px"> - <el-checkbox-group v-model="activityRules[index]" style="width: 100%"> - <el-col :span="24"> - <el-checkbox label="璁㈠崟閲戦浼樻儬" name="type" /> - <el-form-item v-if="activityRules[index].includes('璁㈠崟閲戦浼樻儬')"> - 鍑� - <el-input - style="width: 150px; padding: 0 20px" - v-model="item.discountPrice" - type="number" - placeholder="" - /> - 鍏� - </el-form-item> - </el-col> - <el-col :span="24"> - <el-checkbox v-model="item.freeDelivery" label="鍖呴偖" name="type" /> - </el-col> - <el-col :span="24"> - <el-checkbox label="閫佺Н鍒�" name="type" /> - <el-form-item v-if="activityRules[index].includes('閫佺Н鍒�')"> - 閫� - <el-input - style="width: 150px; padding: 0 20px" - v-model="item.point" - type="number" - placeholder="" - /> - 绉垎 - </el-form-item> - </el-col> - <!-- 浼樻儬鍒稿緟澶勭悊 涔熷彲浠ュ弬鑰冧紭鎯犲姷鐨凷puShowcase--> - <!-- TODO 寰呭疄鐜帮紒--> - <el-col :span="24"> - <el-checkbox label="閫佷紭鎯犲埜" name="type" /> - </el-col> - </el-checkbox-group> - </el-form-item> - </e-form> - </el-row> - </template> - <!-- TODO 瀹炵幇锛氬缓璁敼鎴愭斁鍦ㄦ瘡涓�涓�愭椿鍔ㄥ眰绾с�戠殑涓嬮潰锛屾湁鐐圭被浼间富瀛愯〃 --> - <el-button type="primary" @click="addActivityStratum">娣诲姞娲诲姩灞傜骇</el-button> - </el-form-item> - <el-form-item label="娲诲姩鍟嗗搧" prop="productScope"> - <el-radio-group v-model="formData.productScope"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <!-- TODO锛氭椿鍔ㄥ晢鍝佺殑寮�鍙戯紝鍙互鍙傝�冧紭鎯犲姷鐨勶紝宸茬粡鎼炲ソ鍟︼紱 --> - <el-form-item - v-if="formData.productScope === PromotionProductScopeEnum.SPU.scope" - prop="productSpuIds" - > - <el-select - v-model="formData.productSpuIds" - placeholder="璇烽�夋嫨娲诲姩鍟嗗搧" - clearable - size="small" - multiple - filterable - style="width: 400px" - > - <el-option v-for="item in productSpus" :key="item.id" :label="item.name" :value="item.id"> - <span style="float: left">{{ item.name }}</span> - <span style="float: right; font-size: 13px; color: #8492a6"> - 锟{ (item.price / 100.0).toFixed(2) }} - </span> - </el-option> - </el-select> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { getSpuSimpleList } from '@/api/mall/product/spu' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as RewardActivityApi from '@/api/mall/promotion/reward/rewardActivity' -import { PromotionConditionTypeEnum, PromotionProductScopeEnum } from '@/utils/constants' - -/** 鍒濆鍖� **/ -onMounted(() => { - getSpuSimpleList().then((response) => { - productSpus.value = response - }) -}) -defineOptions({ name: 'ProductBrandForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const productSpus = ref<any[]>([]) // 鍟嗗搧鏁版嵁 -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - startAndEndTime: undefined, - startTime: undefined, - endTime: undefined, - conditionType: PromotionConditionTypeEnum.PRICE.type, - remark: undefined, - productScope: PromotionProductScopeEnum.ALL.scope, - productSpuIds: undefined, - rules: [ - { - limit: undefined, - discountPrice: undefined, - freeDelivery: undefined, - point: undefined, - couponIds: [], - couponCounts: [] - } - ] -}) -const activityRules = reactive([]) // 浼樻儬璁剧疆銆傛瘡涓厓绱犻兘鏄竴涓� []锛屾斁鈥滃寘閭�濄�佲�滈�佺Н鍒嗏�濄�佲�滆鍗曢噾棰濅紭鎯犫�� -const formRules = reactive({ - name: [{ required: true, message: '娲诲姩鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - startAndEndTime: [{ required: true, message: '娲诲姩鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }], - conditionType: [{ required: true, message: '鏉′欢绫诲瀷涓嶈兘涓虹┖', trigger: 'change' }], - productScope: [{ required: true, message: '鍟嗗搧鑼冨洿涓嶈兘涓虹┖', trigger: 'blur' }], - productSpuIds: [{ required: true, message: '鍟嗗搧鑼冨洿涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref([]) // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - let data = await RewardActivityApi.getReward(id) - data.startAndEndTime = [new Date(data.startTime), new Date(data.endTime)] - activityRules.splice(0, activityRules.length) - data.rules.forEach((item) => { - // TODO 鏄笉鏄笉鐢� reactive锛岀洿鎺� [] 灏卞彲浠ヤ簡锛� - let array: string[] = reactive([]) - if (item.freeDelivery) { - array.push('鍖呴偖') - } - if (item.point) { - array.push('閫佺Н鍒�') - } - if (item.discountPrice) { - array.push('璁㈠崟閲戦浼樻儬') - } - activityRules.push(array) - }) - formData.value = data - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 澶勭悊涓嬫暟鎹吋瀹规帴鍙� - formData.value.startTime = +new Date(formData.value.startAndEndTime[0]) - formData.value.endTime = +new Date(formData.value.startAndEndTime[1]) - activityRules.forEach((item, index) => { - formData.value.rules[index].freeDelivery = !!item.includes('鍖呴偖') - if (!item.includes('閫佺Н鍒�')) { - formData.value.rules[index].point = undefined - } - if (!item.includes('璁㈠崟閲戦浼樻儬')) { - formData.value.rules[index].discountPrice = undefined - } - }) - - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as RewardActivityApi.DiscountActivityVO - if (formType.value === 'create') { - await RewardActivityApi.createRewardActivity(data) - message.success(t('common.createSuccess')) - } else { - await RewardActivityApi.updateRewardActivity(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -const addActivityStratum = () => { - formData.value.rules.push({ - limit: undefined, - discountPrice: undefined, - freeDelivery: undefined, - point: undefined, - couponIds: [], - couponCounts: [] - }) - activityRules.push([]) -} - -const deleteActivityRule = (index) => { - formData.value.rules.splice(index, 1) - activityRules.splice(index, 1) -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - startAndEndTime: undefined, - startTime: undefined, - endTime: undefined, - conditionType: PromotionConditionTypeEnum.PRICE.type, - remark: undefined, - productScope: PromotionProductScopeEnum.ALL.scope, - productSpuIds: undefined, - rules: [ - { - limit: undefined, - discountPrice: undefined, - freeDelivery: undefined, - point: undefined, - couponIds: [], - couponCounts: [] - } - ] - } - activityRules.splice(0, activityRules.length) - activityRules.push(reactive([])) - // 瑙e喅涓嬫湁鏃跺埛鏂伴〉闈㈢涓�娆$偣缂栬緫鎶ラ敊 - nextTick(() => { - formRef.value?.resetFields() - }) -} -</script> diff --git a/src/views/mall/promotion/rewardActivity/index.vue b/src/views/mall/promotion/rewardActivity/index.vue deleted file mode 100644 index 4f6f8a6..0000000 --- a/src/views/mall/promotion/rewardActivity/index.vue +++ /dev/null @@ -1,193 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戞弧鍑忛��" url="https://doc.iocoder.cn/mall/promotion-record/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="娲诲姩鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="娲诲姩寮�濮嬫棩鏈�" - end-placeholder="娲诲姩缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['product:brand:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" row-key="id" default-expand-all> - <el-table-column label="娲诲姩鍚嶇О" prop="name" /> - <el-table-column - label="娲诲姩寮�濮嬫椂闂�" - align="center" - prop="startTime" - :formatter="dateFormatter" - /> - <el-table-column - label="娲诲姩缁撴潫鏃堕棿" - align="center" - prop="endTime" - :formatter="dateFormatter" - /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['product:brand:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['product:brand:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <RewardForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as RewardActivityApi from '@/api/mall/promotion/reward/rewardActivity' -import RewardForm from './RewardForm.vue' - -defineOptions({ name: 'PromotionRewardActivity' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await RewardActivityApi.getRewardActivityPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await RewardActivityApi.deleteRewardActivity(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue b/src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue deleted file mode 100644 index 486b71d..0000000 --- a/src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue +++ /dev/null @@ -1,196 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%"> - <Form - ref="formRef" - v-loading="formLoading" - :isCol="true" - :rules="rules" - :schema="allSchemas.formSchema" - > - <!-- 鍏堥�夋嫨 --> - <template #spuId> - <el-button @click="spuSelectRef.open()">閫夋嫨鍟嗗搧</el-button> - <SpuAndSkuList - ref="spuAndSkuListRef" - :rule-config="ruleConfig" - :spu-list="spuList" - :spu-property-list-p="spuPropertyList" - > - <el-table-column align="center" label="绉掓潃搴撳瓨" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number v-model="sku.productConfig.stock" :min="0" class="w-100%" /> - </template> - </el-table-column> - <el-table-column align="center" label="绉掓潃浠锋牸(鍏�)" min-width="168"> - <template #default="{ row: sku }"> - <el-input-number - v-model="sku.productConfig.seckillPrice" - :min="0" - :precision="2" - :step="0.1" - class="w-100%" - /> - </template> - </el-table-column> - </SpuAndSkuList> - </template> - </Form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <SpuSelect ref="spuSelectRef" :isSelectSku="true" @confirm="selectSpu" /> -</template> -<script lang="ts" setup> -import { SpuAndSkuList, SpuProperty, SpuSelect } from '../../components' -import { allSchemas, rules } from './seckillActivity.data' -import { cloneDeep } from 'lodash-es' - -import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity' -import { SeckillProductVO } from '@/api/mall/promotion/seckill/seckillActivity' -import * as ProductSpuApi from '@/api/mall/product/spu' -import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' -import { convertToInteger, formatToFraction } from '@/utils' - -defineOptions({ name: 'PromotionSeckillActivityForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formRef = ref() // 琛ㄥ崟 Ref - -// ================= 鍟嗗搧閫夋嫨鐩稿叧 ================= - -const spuSelectRef = ref() // 鍟嗗搧鍜屽睘鎬ч�夋嫨 Ref -const spuAndSkuListRef = ref() // sku 绉掓潃閰嶇疆缁勪欢Ref -const ruleConfig: RuleConfig[] = [ - { - name: 'productConfig.stock', - rule: (arg) => arg >= 1, - message: '鍟嗗搧绉掓潃搴撳瓨蹇呴』澶т簬绛変簬 1 锛侊紒锛�' - }, - { - name: 'productConfig.seckillPrice', - rule: (arg) => arg >= 0.01, - message: '鍟嗗搧绉掓潃浠锋牸蹇呴』澶т簬绛変簬 0.01 锛侊紒锛�' - } -] -const spuList = ref<SeckillActivityApi.SpuExtension[]>([]) // 閫夋嫨鐨� spu -const spuPropertyList = ref<SpuProperty<SeckillActivityApi.SpuExtension>[]>([]) -const selectSpu = (spuId: number, skuIds: number[]) => { - formRef.value.setValues({ spuId }) - getSpuDetails(spuId, skuIds) -} -/** - * 鑾峰彇 SPU 璇︽儏 - */ -const getSpuDetails = async ( - spuId: number, - skuIds: number[] | undefined, - products?: SeckillProductVO[] -) => { - const spuProperties: SpuProperty<SeckillActivityApi.SpuExtension>[] = [] - const res = (await ProductSpuApi.getSpuDetailList([spuId])) as SeckillActivityApi.SpuExtension[] - if (res.length == 0) { - return - } - spuList.value = [] - // 鍥犱负鍙兘閫夋嫨涓�涓� - const spu = res[0] - const selectSkus = - typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!)) - selectSkus?.forEach((sku) => { - let config: SeckillActivityApi.SeckillProductVO = { - skuId: sku.id!, - stock: 0, - seckillPrice: 0 - } - if (typeof products !== 'undefined') { - const product = products.find((item) => item.skuId === sku.id) - if (product) { - product.seckillPrice = formatToFraction(product.seckillPrice) - } - config = product || config - } - sku.productConfig = config - }) - spu.skus = selectSkus as SeckillActivityApi.SkuExtension[] - spuProperties.push({ - spuId: spu.id!, - spuDetail: spu, - propertyList: getPropertyList(spu) - }) - spuList.value.push(spu) - spuPropertyList.value = spuProperties -} - -// ================= end ================= - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - await resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - const data = (await SeckillActivityApi.getSeckillActivity( - id - )) as SeckillActivityApi.SeckillActivityVO - await getSpuDetails(data.spuId!, data.products?.map((sku) => sku.skuId), data.products) - formRef.value.setValues(data) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.getElFormRef().validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - // 鑾峰彇绉掓潃鍟嗗搧閰嶇疆 - const products = cloneDeep(spuAndSkuListRef.value.getSkuConfigs('productConfig')) - products.forEach((item: SeckillProductVO) => { - item.seckillPrice = convertToInteger(item.seckillPrice) - }) - const data = formRef.value.formModel as SeckillActivityApi.SeckillActivityVO - data.products = products - // 鐪熸鎻愪氦 - if (formType.value === 'create') { - await SeckillActivityApi.createSeckillActivity(data) - message.success(t('common.createSuccess')) - } else { - await SeckillActivityApi.updateSeckillActivity(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = async () => { - spuList.value = [] - spuPropertyList.value = [] - await nextTick() - formRef.value.getElFormRef().resetFields() -} -</script> diff --git a/src/views/mall/promotion/seckill/activity/index.vue b/src/views/mall/promotion/seckill/activity/index.vue deleted file mode 100644 index bffe265..0000000 --- a/src/views/mall/promotion/seckill/activity/index.vue +++ /dev/null @@ -1,256 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戠鏉�娲诲姩" url="https://doc.iocoder.cn/mall/promotion-seckill/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="娲诲姩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:seckill-activity:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="娲诲姩缂栧彿" prop="id" min-width="80" /> - <el-table-column label="娲诲姩鍚嶇О" prop="name" min-width="140" /> - <el-table-column - label="绉掓潃鏃舵" - prop="configIds" - width="220px" - :show-overflow-tooltip="false" - > - <template #default="scope"> - <el-tag v-for="(configId, index) in scope.row.configIds" :key="index" class="mr-5px"> - {{ formatConfigNames(configId) }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="娲诲姩鏃堕棿" min-width="210"> - <template #default="scope"> - {{ formatDate(scope.row.startTime, 'YYYY-MM-DD') }} - ~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }} - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍥剧墖" prop="spuName" min-width="80"> - <template #default="scope"> - <el-image - :src="scope.row.picUrl" - class="h-40px w-40px" - :preview-src-list="[scope.row.picUrl]" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鏍囬" prop="spuName" min-width="300" /> - <el-table-column - label="鍘熶环" - prop="marketPrice" - min-width="100" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鍘熶环" prop="marketPrice" min-width="100" /> - <el-table-column label="绉掓潃浠�" prop="seckillPrice" min-width="100"> - <template #default="scope"> - {{ formatSeckillPrice(scope.row.products) }} - </template> - </el-table-column> - <el-table-column label="娲诲姩鐘舵��" align="center" prop="status" min-width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="搴撳瓨" align="center" prop="stock" min-width="80" /> - <el-table-column label="鎬诲簱瀛�" align="center" prop="totalStock" min-width="80" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:seckill-activity:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleClose(scope.row.id)" - v-if="scope.row.status === 0" - v-hasPermi="['promotion:seckill-activity:close']" - > - 鍏抽棴 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-else - v-hasPermi="['promotion:seckill-activity:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SeckillActivityForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity' -import { SeckillConfigApi } from '@/api/mall/promotion/seckill/seckillConfig' -import SeckillActivityForm from './SeckillActivityForm.vue' -import { formatDate } from '@/utils/formatTime' -import { fenToYuanFormat } from '@/utils/formatter' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'SeckillActivity' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SeckillActivityApi.getSeckillActivityPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍏抽棴鎸夐挳鎿嶄綔 */ -const handleClose = async (id: number) => { - try { - // 鍏抽棴鐨勪簩娆$‘璁� - await message.confirm('纭鍏抽棴璇ョ鏉�娲诲姩鍚楋紵') - // 鍙戣捣鍏抽棴 - await SeckillActivityApi.closeSeckillActivity(id) - message.success('鍏抽棴鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SeckillActivityApi.deleteSeckillActivity(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -const configList = ref([]) // 鏃舵閰嶇疆绮剧畝鍒楄〃 -const formatConfigNames = (configId) => { - const config = configList.value.find((item) => item.id === configId) - return config != null ? `${config.name}[${config.startTime} ~ ${config.endTime}]` : '' -} - -const formatSeckillPrice = (products) => { - const seckillPrice = Math.min(...products.map((item) => item.seckillPrice)) - return `锟�${fenToYuan(seckillPrice)}` -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱绉掓潃鏃堕棿娈� - configList.value = await SeckillConfigApi.getSimpleSeckillConfigList() -}) -</script> diff --git a/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts b/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts deleted file mode 100644 index b6e6422..0000000 --- a/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type { CrudSchema } from '@/hooks/web/useCrudSchemas' -import { dateFormatter2 } from '@/utils/formatTime' -import { SeckillConfigApi } from '@/api/mall/promotion/seckill/seckillConfig' - -// 琛ㄥ崟鏍¢獙 -export const rules = reactive({ - spuId: [required], - name: [required], - startTime: [required], - endTime: [required], - sort: [required], - configIds: [required], - totalLimitCount: [required], - singleLimitCount: [required], - totalStock: [required] -}) - -// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ -const crudSchemas = reactive<CrudSchema[]>([ - { - label: '绉掓潃娲诲姩鍚嶇О', - field: 'name', - isSearch: true, - form: { - colProps: { - span: 24 - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩寮�濮嬫椂闂�', - field: 'startTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '娲诲姩缁撴潫鏃堕棿', - field: 'endTime', - formatter: dateFormatter2, - isSearch: true, - search: { - component: 'DatePicker', - componentProps: { - valueFormat: 'YYYY-MM-DD', - type: 'daterange' - } - }, - form: { - component: 'DatePicker', - componentProps: { - type: 'date', - valueFormat: 'x' - } - }, - table: { - width: 120 - } - }, - { - label: '绉掓潃鏃舵', - field: 'configIds', - form: { - component: 'Select', - componentProps: { - multiple: true, - optionsAlias: { - labelField: 'name', - valueField: 'id' - } - }, - api: SeckillConfigApi.getSimpleSeckillConfigList - }, - table: { - width: 300 - } - }, - { - label: '鎬婚檺璐暟閲�', - field: 'totalLimitCount', - form: { - component: 'InputNumber', - value: 0 - }, - table: { - width: 120 - } - }, - { - label: '鍗曟闄愬鏁伴噺', - field: 'singleLimitCount', - form: { - component: 'InputNumber', - value: 0 - }, - table: { - width: 120 - } - }, - { - label: '鎺掑簭', - field: 'sort', - form: { - component: 'InputNumber', - value: 0 - }, - table: { - width: 80 - } - }, - { - label: '绉掓潃娲诲姩鍟嗗搧', - field: 'spuId', - isTable: true, - isSearch: false, - form: { - colProps: { - span: 24 - } - }, - table: { - width: 300 - } - }, - { - label: '澶囨敞', - field: 'remark', - isSearch: false, - form: { - component: 'Input', - componentProps: { - type: 'textarea', - rows: 4 - }, - colProps: { - span: 24 - } - }, - table: { - width: 300 - } - } -]) -export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue deleted file mode 100644 index a7ce5fe..0000000 --- a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue +++ /dev/null @@ -1,133 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="绉掓潃鏃舵鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ鏉�鏃舵鍚嶇О" /> - </el-form-item> - <el-form-item label="寮�濮嬫椂闂寸偣" prop="startTime"> - <el-time-picker - v-model="formData.startTime" - value-format="HH:mm:ss" - placeholder="閫夋嫨寮�濮嬫椂闂寸偣" - /> - </el-form-item> - <el-form-item label="缁撴潫鏃堕棿鐐�" prop="endTime"> - <el-time-picker - v-model="formData.endTime" - value-format="HH:mm:ss" - placeholder="閫夋嫨缁撴潫鏃堕棿鐐�" - /> - </el-form-item> - <el-form-item label="绉掓潃杞挱鍥�" prop="sliderPicUrls"> - <UploadImgs v-model="formData.sliderPicUrls" placeholder="璇疯緭鍏ョ鏉�杞挱鍥�" /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { SeckillConfigApi, SeckillConfigVO } from '@/api/mall/promotion/seckill/seckillConfig.ts' -import { CommonStatusEnum } from '@/utils/constants' - -/** 绉掓潃鏃舵 琛ㄥ崟 */ -defineOptions({ name: 'SeckillConfigForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - startTime: undefined, - endTime: undefined, - sliderPicUrls: undefined, - status: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '绉掓潃鏃舵鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - startTime: [{ required: true, message: '寮�濮嬫椂闂寸偣涓嶈兘涓虹┖', trigger: 'blur' }], - endTime: [{ required: true, message: '缁撴潫鏃堕棿鐐逛笉鑳戒负绌�', trigger: 'blur' }], - status: [{ required: true, message: '娲诲姩鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SeckillConfigApi.getSeckillConfig(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - await formRef.value.validate() - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as SeckillConfigVO - if (formType.value === 'create') { - await SeckillConfigApi.createSeckillConfig(data) - message.success(t('common.createSuccess')) - } else { - await SeckillConfigApi.updateSeckillConfig(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - startTime: undefined, - endTime: undefined, - sliderPicUrls: [], - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/promotion/seckill/config/index.vue b/src/views/mall/promotion/seckill/config/index.vue deleted file mode 100644 index 9fa2c1e..0000000 --- a/src/views/mall/promotion/seckill/config/index.vue +++ /dev/null @@ -1,211 +0,0 @@ -<template> - <doc-alert title="銆愯惀閿�銆戠鏉�娲诲姩" url="https://doc.iocoder.cn/mall/promotion-seckill/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="108px" - > - <el-form-item label="绉掓潃鏃舵鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ョ鏉�鏃舵鍚嶇О" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娲诲姩鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨娲诲姩鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['promotion:seckill-config:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="绉掓潃鏃舵鍚嶇О" align="center" prop="name" /> - <el-table-column label="寮�濮嬫椂闂寸偣" align="center" prop="startTime" /> - <el-table-column label="缁撴潫鏃堕棿鐐�" align="center" prop="endTime" /> - <el-table-column label="绉掓潃杞挱鍥�" align="center" prop="sliderPicUrls"> - <template #default="scope"> - <el-image - class="h-40px max-w-40px" - v-for="(url, index) in scope?.row.sliderPicUrls" - :key="index" - :src="url" - :preview-src-list="scope?.row.sliderPicUrls" - :initial-index="index" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="娲诲姩鐘舵��" align="center" prop="status"> - <template #default="scope"> - <el-switch - v-model="scope.row.status" - :active-value="0" - :inactive-value="1" - @change="handleStatusChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['promotion:seckill-config:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['promotion:seckill-config:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SeckillConfigForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import { SeckillConfigApi, SeckillConfigVO } from '@/api/mall/promotion/seckill/seckillConfig.ts' -import SeckillConfigForm from './SeckillConfigForm.vue' -import { CommonStatusEnum } from '@/utils/constants' - -/** 绉掓潃鏃舵 鍒楄〃 */ -defineOptions({ name: 'SeckillConfig' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<SeckillConfigVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SeckillConfigApi.getSeckillConfigPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SeckillConfigApi.deleteSeckillConfig(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 淇敼鐢ㄦ埛鐘舵�� */ -const handleStatusChange = async (row: SeckillConfigVO) => { - try { - // 淇敼鐘舵�佺殑浜屾纭 - const text = row.status === CommonStatusEnum.ENABLE ? '鍚敤' : '鍋滅敤' - await message.confirm('纭瑕�' + text + '"' + row.name + '"娲诲姩鍚�?') - // 鍙戣捣淇敼鐘舵�� - await SeckillConfigApi.updateSeckillConfigStatus(row.id, row.status) - // 鍒锋柊鍒楄〃 - await getList() - } catch { - // 鍙栨秷鍚庯紝杩涜鎭㈠鎸夐挳 - row.status = - row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/statistics/member/components/MemberFunnelCard.vue b/src/views/mall/statistics/member/components/MemberFunnelCard.vue deleted file mode 100644 index 609c679..0000000 --- a/src/views/mall/statistics/member/components/MemberFunnelCard.vue +++ /dev/null @@ -1,121 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <div class="my--1.5 flex flex-row items-center justify-between"> - <CardTitle title="浼氬憳姒傝" /> - <!-- 鏌ヨ鏉′欢 --> - <ShortcutDateRangePicker @change="handleTimeRangeChange" /> - </div> - </template> - <div class="min-w-225 py-1.75" v-loading="loading"> - <div class="relative h-24 flex"> - <div class="h-full w-75% bg-blue-50 <lg:w-35% <xl:w-55%"> - <div class="ml-15 h-full flex flex-col justify-center"> - <div class="font-bold"> - 娉ㄥ唽鐢ㄦ埛鏁伴噺锛歿{ analyseData?.comparison?.value?.registerUserCount || 0 }} - </div> - <div class="mt-2 text-3.5"> - 鐜瘮澧為暱鐜囷細{{ - calculateRelativeRate( - analyseData?.comparison?.value?.registerUserCount, - analyseData?.comparison?.reference?.registerUserCount - ) - }}% - </div> - </div> - </div> - <div - class="trapezoid1 ml--38.5 mt-1.5 h-full w-77 flex flex-col items-center justify-center bg-blue-5 text-3.5 text-white" - > - <span class="text-6 font-bold">{{ analyseData?.visitUserCount || 0 }}</span> - <span>璁垮</span> - </div> - </div> - <div class="relative h-24 flex"> - <div class="h-full w-75% flex bg-cyan-50 <lg:w-35% <xl:w-55%"> - <div class="ml-15 h-full flex flex-col justify-center"> - <div class="font-bold"> - 娲昏穬鐢ㄦ埛鏁伴噺锛歿{ analyseData?.comparison?.value?.visitUserCount || 0 }} - </div> - <div class="mt-2 text-3.5"> - 鐜瘮澧為暱鐜囷細{{ - calculateRelativeRate( - analyseData?.comparison?.value?.visitUserCount, - analyseData?.comparison?.reference?.visitUserCount - ) - }}% - </div> - </div> - </div> - <div - class="trapezoid2 ml--28 mt-1.7 h-25 w-56 flex flex-col items-center justify-center bg-cyan-5 text-3.5 text-white" - > - <span class="text-6 font-bold">{{ analyseData?.orderUserCount || 0 }}</span> - <span>涓嬪崟</span> - </div> - </div> - <div class="relative h-24 flex"> - <div class="w-75% flex bg-slate-50 <lg:w-35% <xl:w-55%"> - <div class="ml-15 h-full flex flex-row gap-x-16"> - <div class="flex flex-col justify-center"> - <div class="font-bold"> - 鍏呭�肩敤鎴锋暟閲忥細{{ analyseData?.comparison?.value?.rechargeUserCount || 0 }} - </div> - <div class="mt-2 text-3.5"> - 鐜瘮澧為暱鐜囷細{{ - calculateRelativeRate( - analyseData?.comparison?.value?.rechargeUserCount, - analyseData?.comparison?.reference?.rechargeUserCount - ) - }}% - </div> - </div> - <div class="flex flex-col justify-center"> - <div class="font-bold">瀹㈠崟浠凤細{{ fenToYuan(analyseData?.atv || 0) }}</div> - </div> - </div> - </div> - <div - class="trapezoid3 ml--18 mt-3.25 h-23 w-36 flex flex-col items-center justify-center bg-slate-5 text-3.5 text-white" - > - <span class="text-6 font-bold">{{ analyseData?.payUserCount || 0 }}</span> - <span>鎴愪氦鐢ㄦ埛</span> - </div> - </div> - </div> - </el-card> -</template> -<script lang="ts" setup> -import * as MemberStatisticsApi from '@/api/mall/statistics/member' -import dayjs from 'dayjs' -import { calculateRelativeRate, fenToYuan } from '@/utils' -import { MemberAnalyseRespVO } from '@/api/mall/statistics/member' -import { CardTitle } from '@/components/Card' - -/** 浼氬憳姒傝鍗$墖 */ -defineOptions({ name: 'MemberFunnelCard' }) - -const loading = ref(true) // 鍔犺浇涓� -const analyseData = ref<MemberAnalyseRespVO>() // 浼氬憳鍒嗘瀽鏁版嵁 - -/** 鏌ヨ浼氬憳姒傝鏁版嵁鍒楄〃 */ -const handleTimeRangeChange = async (times: [dayjs.ConfigType, dayjs.ConfigType]) => { - loading.value = true - // 鏌ヨ鏁版嵁 - analyseData.value = await MemberStatisticsApi.getMemberAnalyse({ times }) - loading.value = false -} -</script> -<style lang="scss" scoped> -.trapezoid1 { - transform: perspective(5em) rotateX(-11deg); -} - -.trapezoid2 { - transform: perspective(7em) rotateX(-20deg); -} - -.trapezoid3 { - transform: perspective(3em) rotateX(-13deg); -} -</style> diff --git a/src/views/mall/statistics/member/components/MemberTerminalCard.vue b/src/views/mall/statistics/member/components/MemberTerminalCard.vue deleted file mode 100644 index 7bbab76..0000000 --- a/src/views/mall/statistics/member/components/MemberTerminalCard.vue +++ /dev/null @@ -1,69 +0,0 @@ -<template> - <el-card shadow="never" v-loading="loading"> - <template #header> - <CardTitle title="浼氬憳缁堢" /> - </template> - <Echart :height="300" :options="terminalChartOptions" /> - </el-card> -</template> -<script lang="ts" setup> -import * as MemberStatisticsApi from '@/api/mall/statistics/member' -import { EChartsOption } from 'echarts' -import { MemberTerminalStatisticsRespVO } from '@/api/mall/statistics/member' -import { DICT_TYPE, DictDataType, getIntDictOptions } from '@/utils/dict' -import { CardTitle } from '@/components/Card' - -/** 浼氬憳缁堢鍗$墖 */ -defineOptions({ name: 'MemberTerminalCard' }) - -const loading = ref(true) // 鍔犺浇涓� - -/** 浼氬憳缁堢缁熻鍥鹃厤缃� */ -const terminalChartOptions = reactive<EChartsOption>({ - tooltip: { - trigger: 'item', - confine: true, - formatter: '{a} <br/>{b} : {c} ({d}%)' - }, - legend: { - orient: 'vertical', - left: 'right' - }, - roseType: 'area', - series: [ - { - name: '浼氬憳缁堢', - type: 'pie', - label: { - show: false - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 鎸夌収缁堢锛屾煡璇細鍛樼粺璁″垪琛� */ -const getMemberTerminalStatisticsList = async () => { - loading.value = true - const list = await MemberStatisticsApi.getMemberTerminalStatisticsList() - const dictDataList = getIntDictOptions(DICT_TYPE.TERMINAL) - terminalChartOptions.series![0].data = dictDataList.map((dictData: DictDataType) => { - const userCount = list.find( - (item: MemberTerminalStatisticsRespVO) => item.terminal === dictData.value - )?.userCount - return { - name: dictData.label, - value: userCount || 0 - } - }) - loading.value = false -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getMemberTerminalStatisticsList() -}) -</script> diff --git a/src/views/mall/statistics/member/index.vue b/src/views/mall/statistics/member/index.vue deleted file mode 100644 index 0e1bbaf..0000000 --- a/src/views/mall/statistics/member/index.vue +++ /dev/null @@ -1,313 +0,0 @@ -<template> - <doc-alert title="銆愮粺璁°�戜細鍛樸�佸晢鍝併�佷氦鏄撶粺璁�" url="https://doc.iocoder.cn/mall/statistics/" /> - - <div class="flex flex-col"> - <el-row :gutter="16" class="summary"> - <el-col v-loading="loading" :sm="6" :xs="12"> - <SummaryCard - :value="summary?.userCount || 0" - icon="fa-solid:users" - icon-bg-color="text-blue-500" - icon-color="bg-blue-100" - title="绱浼氬憳鏁�" - /> - </el-col> - <el-col v-loading="loading" :sm="6" :xs="12"> - <SummaryCard - :value="summary?.rechargeUserCount || 0" - icon="fa-solid:user" - icon-bg-color="text-purple-500" - icon-color="bg-purple-100" - title="绱鍏呭�间汉鏁�" - /> - </el-col> - <el-col v-loading="loading" :sm="6" :xs="12"> - <SummaryCard - :decimals="2" - :value="fenToYuan(summary?.rechargePrice || 0)" - icon="fa-solid:money-check-alt" - icon-bg-color="text-yellow-500" - icon-color="bg-yellow-100" - prefix="锟�" - title="绱鍏呭�奸噾棰�" - /> - </el-col> - <el-col v-loading="loading" :sm="6" :xs="12"> - <SummaryCard - :decimals="2" - :value="fenToYuan(summary?.expensePrice || 0)" - icon="fa-solid:yen-sign" - icon-bg-color="text-green-500" - icon-color="bg-green-100" - prefix="锟�" - title="绱娑堣垂閲戦" - /> - </el-col> - </el-row> - <el-row :gutter="16" class="mb-4"> - <el-col :md="18" :sm="24"> - <!-- 浼氬憳姒傝 --> - <MemberFunnelCard /> - </el-col> - <el-col :md="6" :sm="24"> - <!-- 浼氬憳缁堢 --> - <MemberTerminalCard /> - </el-col> - </el-row> - <el-row :gutter="16"> - <el-col :md="18" :sm="24"> - <el-card shadow="never"> - <template #header> - <CardTitle title="浼氬憳鍦板煙鍒嗗竷" /> - </template> - <el-row v-loading="loading"> - <el-col :span="10"> - <Echart :height="300" :options="areaChartOptions" /> - </el-col> - <el-col :span="14"> - <el-table :data="areaStatisticsList" :height="300"> - <el-table-column - :sort-method="(obj1, obj2) => obj1.areaName.localeCompare(obj2.areaName, 'zh-CN')" - align="center" - label="鐪佷唤" - min-width="80" - prop="areaName" - show-overflow-tooltip - sortable - /> - <el-table-column - align="center" - label="浼氬憳鏁伴噺" - min-width="105" - prop="userCount" - sortable - /> - <el-table-column - align="center" - label="璁㈠崟鍒涘缓鏁伴噺" - min-width="135" - prop="orderCreateUserCount" - sortable - /> - <el-table-column - align="center" - label="璁㈠崟鏀粯鏁伴噺" - min-width="135" - prop="orderPayUserCount" - sortable - /> - <el-table-column - :formatter="fenToYuanFormat" - align="center" - label="璁㈠崟鏀粯閲戦" - min-width="135" - prop="orderPayPrice" - sortable - /> - </el-table> - </el-col> - </el-row> - </el-card> - </el-col> - <el-col :md="6" :sm="24"> - <el-card v-loading="loading" shadow="never"> - <template #header> - <CardTitle title="浼氬憳鎬у埆姣斾緥" /> - </template> - <Echart :height="300" :options="sexChartOptions" /> - </el-card> - </el-col> - </el-row> - </div> -</template> -<script lang="ts" setup> -import * as MemberStatisticsApi from '@/api/mall/statistics/member' -import { - MemberAreaStatisticsRespVO, - MemberSexStatisticsRespVO, - MemberSummaryRespVO, - MemberTerminalStatisticsRespVO -} from '@/api/mall/statistics/member' -import SummaryCard from '@/components/SummaryCard/index.vue' -import { EChartsOption } from 'echarts' -import china from '@/assets/map/json/china.json' -import { areaReplace, fenToYuan } from '@/utils' -import { DICT_TYPE, DictDataType, getIntDictOptions } from '@/utils/dict' -import echarts from '@/plugins/echarts' -import { fenToYuanFormat } from '@/utils/formatter' -import MemberFunnelCard from './components/MemberFunnelCard.vue' -import MemberTerminalCard from './components/MemberTerminalCard.vue' -import { CardTitle } from '@/components/Card' - -/** 浼氬憳缁熻 */ -defineOptions({ name: 'MemberStatistics' }) - -const loading = ref(true) // 鍔犺浇涓� -const summary = ref<MemberSummaryRespVO>() // 浼氬憳缁熻鏁版嵁 -const areaStatisticsList = shallowRef<MemberAreaStatisticsRespVO[]>() // 鐪佷唤浼氬憳缁熻 - -// 娉ㄥ唽鍦板浘 -echarts?.registerMap('china', china as any) - -/** 浼氬憳缁堢缁熻鍥鹃厤缃� */ -const terminalChartOptions = reactive<EChartsOption>({ - tooltip: { - trigger: 'item', - confine: true, - formatter: '{a} <br/>{b} : {c} ({d}%)' - }, - legend: { - orient: 'vertical', - left: 'right' - }, - roseType: 'area', - series: [ - { - name: '浼氬憳缁堢', - type: 'pie', - label: { - show: false - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -/** 浼氬憳鎬у埆缁熻鍥鹃厤缃� */ -const sexChartOptions = reactive<EChartsOption>({ - tooltip: { - trigger: 'item', - confine: true, - formatter: '{a} <br/>{b} : {c} ({d}%)' - }, - legend: { - orient: 'vertical', - left: 'right' - }, - roseType: 'area', - series: [ - { - name: '浼氬憳鎬у埆', - type: 'pie', - label: { - show: false - }, - labelLine: { - show: false - }, - data: [] - } - ] -}) as EChartsOption - -const areaChartOptions = reactive<EChartsOption>({ - tooltip: { - trigger: 'item', - formatter: (params: any) => { - return `${params?.data?.areaName || params?.name}<br/> -浼氬憳鏁伴噺锛�${params?.data?.userCount || 0}<br/> -璁㈠崟鍒涘缓鏁伴噺锛�${params?.data?.orderCreateUserCount || 0}<br/> -璁㈠崟鏀粯鏁伴噺锛�${params?.data?.orderPayUserCount || 0}<br/> -璁㈠崟鏀粯閲戦锛�${fenToYuan(params?.data?.orderPayPrice || 0)}` - } - }, - visualMap: { - text: ['楂�', '浣�'], - realtime: false, - calculable: true, - top: 'middle', - inRange: { - color: ['#fff', '#3b82f6'] - } - }, - series: [ - { - name: '浼氬憳鍦板煙鍒嗗竷', - type: 'map', - map: 'china', - roam: false, - selectedMode: false, - data: [] - } - ] -}) as EChartsOption - -/** 鏌ヨ浼氬憳缁熻 */ -const getMemberSummary = async () => { - summary.value = await MemberStatisticsApi.getMemberSummary() -} - -/** 鎸夌収鐪佷唤锛屾煡璇細鍛樼粺璁″垪琛� */ -const getMemberAreaStatisticsList = async () => { - const list = await MemberStatisticsApi.getMemberAreaStatisticsList() - areaStatisticsList.value = list.map((item: MemberAreaStatisticsRespVO) => { - return { - ...item, - areaName: areaReplace(item.areaName) - } - }) - let min = 0 - let max = 0 - areaChartOptions.series![0].data = areaStatisticsList.value.map((item) => { - min = Math.min(min, item.orderPayUserCount || 0) - max = Math.max(max, item.orderPayUserCount || 0) - return { ...item, name: item.areaName, value: item.orderPayUserCount || 0 } - }) - areaChartOptions.visualMap!['min'] = min - areaChartOptions.visualMap!['max'] = max -} - -/** 鎸夌収鎬у埆锛屾煡璇細鍛樼粺璁″垪琛� */ -const getMemberSexStatisticsList = async () => { - const list = await MemberStatisticsApi.getMemberSexStatisticsList() - const dictDataList = getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX) - dictDataList.push({ label: '鏈煡', value: null } as any) - sexChartOptions.series![0].data = dictDataList.map((dictData: DictDataType) => { - const userCount = list.find( - (item: MemberSexStatisticsRespVO) => item.sex === dictData.value - )?.userCount - return { - name: dictData.label, - value: userCount || 0 - } - }) -} - -/** 鎸夌収缁堢锛屾煡璇細鍛樼粺璁″垪琛� */ -const getMemberTerminalStatisticsList = async () => { - const list = await MemberStatisticsApi.getMemberTerminalStatisticsList() - const dictDataList = getIntDictOptions(DICT_TYPE.TERMINAL) - dictDataList.push({ label: '鏈煡', value: null } as any) - terminalChartOptions.series![0].data = dictDataList.map((dictData: DictDataType) => { - const userCount = list.find( - (item: MemberTerminalStatisticsRespVO) => item.terminal === dictData.value - )?.userCount - return { - name: dictData.label, - value: userCount || 0 - } - }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - loading.value = true - await Promise.all([ - getMemberSummary(), - getMemberTerminalStatisticsList(), - getMemberAreaStatisticsList(), - getMemberSexStatisticsList() - ]) - loading.value = false -}) -</script> -<style lang="scss" scoped> -.summary { - .el-col { - margin-bottom: 1rem; - } -} -</style> diff --git a/src/views/mall/statistics/product/components/ProductRank.vue b/src/views/mall/statistics/product/components/ProductRank.vue deleted file mode 100644 index cb513bc..0000000 --- a/src/views/mall/statistics/product/components/ProductRank.vue +++ /dev/null @@ -1,101 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <!-- 鏍囬 --> - <div class="flex flex-row items-center justify-between"> - <CardTitle title="鍟嗗搧鎺掕" /> - <!-- 鏌ヨ鏉′欢 --> - <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="handleDateRangeChange" /> - </div> - </template> - <!-- 鎺掕鍒楄〃 --> - <el-table v-loading="loading" :data="list" @sort-change="handleSortChange"> - <el-table-column label="鍟嗗搧ID" prop="spuId" min-width="70" /> - <el-table-column label="鍟嗗搧鍥剧墖" align="center" prop="picUrl" width="80"> - <template #default="{ row }"> - <el-image - :src="row.picUrl" - :preview-src-list="[row.picUrl]" - class="h-30px w-30px" - preview-teleported - /> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍚嶇О" prop="name" min-width="200" :show-overflow-tooltip="true" /> - <el-table-column label="娴忚閲�" prop="browseCount" min-width="90" sortable="custom" /> - <el-table-column label="璁垮鏁�" prop="browseUserCount" min-width="90" sortable="custom" /> - <el-table-column label="鍔犺喘浠舵暟" prop="cartCount" min-width="105" sortable="custom" /> - <el-table-column label="涓嬪崟浠舵暟" prop="orderCount" min-width="105" sortable="custom" /> - <el-table-column label="鏀粯浠舵暟" prop="orderPayCount" min-width="105" sortable="custom" /> - <el-table-column label="鏀粯閲戦" prop="orderPayPrice" min-width="105" sortable="custom" /> - <el-table-column label="鏀惰棌鏁�" prop="favoriteCount" min-width="90" sortable="custom" /> - <el-table-column - label="璁垮-鏀粯杞寲鐜�(%)" - prop="browseConvertPercent" - min-width="180" - sortable="custom" - :formatter="formatConvertRate" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getSpuList" - /> - </el-card> -</template> -<script lang="ts" setup> -import { ProductStatisticsApi, ProductStatisticsVO } from '@/api/mall/statistics/product' -import { CardTitle } from '@/components/Card' -import { buildSortingField } from '@/utils' - -/** 鍟嗗搧鎺掕 */ -defineOptions({ name: 'ProductRank' }) - -// 鏍煎紡鍖栵細璁垮-鏀粯杞寲鐜� -const formatConvertRate = (row: ProductStatisticsVO) => { - return `${row.browseConvertPercent}%` -} - -const handleSortChange = (params: any) => { - queryParams.sortingFields = [buildSortingField(params)] - getSpuList() -} - -const handleDateRangeChange = (times: any[]) => { - queryParams.times = times as [] - getSpuList() -} - -const shortcutDateRangePicker = ref() -// 鏌ヨ鍙傛暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - times: [], - sortingFields: {} -}) -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<ProductStatisticsVO[]>([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌ヨ鍟嗗搧鍒楄〃 */ -const getSpuList = async () => { - loading.value = true - try { - const data = await ProductStatisticsApi.getProductStatisticsRankPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getSpuList() -}) -</script> -<style lang="scss" scoped></style> diff --git a/src/views/mall/statistics/product/components/ProductSummary.vue b/src/views/mall/statistics/product/components/ProductSummary.vue deleted file mode 100644 index 0669223..0000000 --- a/src/views/mall/statistics/product/components/ProductSummary.vue +++ /dev/null @@ -1,304 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <!-- 鏍囬 --> - <div class="flex flex-row items-center justify-between"> - <CardTitle title="鍟嗗搧姒傚喌" /> - <!-- 鏌ヨ鏉′欢 --> - <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getProductTrendData"> - <el-button - class="ml-4" - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['statistics:product:export']" - > - <Icon icon="ep:download" class="mr-1" />瀵煎嚭 - </el-button> - </ShortcutDateRangePicker> - </div> - </template> - <!-- 缁熻鍊� --> - <el-row :gutter="16"> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="鍟嗗搧娴忚閲�" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎵�鏈夊晢鍝佽鎯呴〉琚闂殑娆℃暟锛屼竴涓汉鍦ㄧ粺璁℃椂闂村唴璁块棶澶氭璁颁负澶氭" - icon="ep:view" - icon-color="bg-blue-100" - icon-bg-color="text-blue-500" - prefix="" - :decimals="0" - :value="trendSummary?.value?.browseCount || 0" - :percent=" - calculateRelativeRate( - trendSummary?.value?.browseCount, - trendSummary?.reference?.browseCount - ) - " - /> - </el-col> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="鍟嗗搧璁垮鏁�" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝璁块棶浠讳綍鍟嗗搧璇︽儏椤电殑浜烘暟锛屼竴涓汉鍦ㄧ粺璁℃椂闂磋寖鍥村唴璁块棶澶氭鍙涓轰竴涓�" - icon="ep:user-filled" - icon-color="bg-purple-100" - icon-bg-color="text-purple-500" - prefix="" - :decimals="0" - :value="trendSummary?.value?.browseUserCount || 0" - :percent=" - calculateRelativeRate( - trendSummary?.value?.browseUserCount, - trendSummary?.reference?.browseUserCount - ) - " - /> - </el-col> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="鏀粯浠舵暟" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛浠樻璁㈠崟鐨勫晢鍝佷欢鏁颁箣鍜�" - icon="fa-solid:money-check-alt" - icon-color="bg-yellow-100" - icon-bg-color="text-yellow-500" - prefix="" - :decimals="0" - :value="trendSummary?.value?.orderPayCount || 0" - :percent=" - calculateRelativeRate( - trendSummary?.value?.orderPayCount, - trendSummary?.reference?.orderPayCount - ) - " - /> - </el-col> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="鏀粯閲戦" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛浠樻璁㈠崟鐨勫晢鍝侀噾棰濅箣鍜�" - icon="ep:warning-filled" - icon-color="bg-green-100" - icon-bg-color="text-green-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.orderPayPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.orderPayPrice, - trendSummary?.reference?.orderPayPrice - ) - " - /> - </el-col> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="閫�娆句欢鏁�" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛閫�娆剧殑鍟嗗搧浠舵暟涔嬪拰" - icon="fa-solid:wallet" - icon-color="bg-cyan-100" - icon-bg-color="text-cyan-500" - prefix="" - :decimals="0" - :value="trendSummary?.value?.afterSaleCount || 0" - :percent=" - calculateRelativeRate( - trendSummary?.value?.afterSaleCount, - trendSummary?.reference?.afterSaleCount - ) - " - /> - </el-col> - <el-col :xl="4" :md="8" :sm="24"> - <SummaryCard - title="閫�娆鹃噾棰�" - tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛閫�娆剧殑鍟嗗搧閲戦涔嬪拰" - icon="fa-solid:award" - icon-color="bg-yellow-100" - icon-bg-color="text-yellow-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.afterSaleRefundPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.afterSaleRefundPrice, - trendSummary?.reference?.afterSaleRefundPrice - ) - " - /> - </el-col> - </el-row> - <!-- 鎶樼嚎鍥� --> - <el-skeleton :loading="trendLoading" animated> - <Echart :height="500" :options="lineChartOptions" /> - </el-skeleton> - </el-card> -</template> -<script lang="ts" setup> -import { ProductStatisticsApi, ProductStatisticsVO } from '@/api/mall/statistics/product' -import SummaryCard from '@/components/SummaryCard/index.vue' -import { EChartsOption } from 'echarts' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' -import { calculateRelativeRate, fenToYuan } from '@/utils' -import download from '@/utils/download' -import { CardTitle } from '@/components/Card' -import * as DateUtil from '@/utils/formatTime' -import dayjs from 'dayjs' - -/** 鍟嗗搧姒傚喌 */ -defineOptions({ name: 'ProductSummary' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const trendLoading = ref(true) // 鍟嗗搧鐘舵�佸姞杞戒腑 -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const trendSummary = ref<DataComparisonRespVO<ProductStatisticsVO>>() // 鍟嗗搧鐘跺喌缁熻鏁版嵁 -const shortcutDateRangePicker = ref() - -/** 鎶樼嚎鍥鹃厤缃� */ -const lineChartOptions = reactive<EChartsOption>({ - dataset: { - dimensions: ['time', 'browseCount', 'browseUserCount', 'orderPayPrice', 'afterSaleRefundPrice'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - top: 80, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { name: '鍟嗗搧娴忚閲�', type: 'line', smooth: true, itemStyle: { color: '#B37FEB' } }, - { name: '鍟嗗搧璁垮鏁�', type: 'line', smooth: true, itemStyle: { color: '#FFAB2B' } }, - { name: '鏀粯閲戦', type: 'bar', smooth: true, yAxisIndex: 1, itemStyle: { color: '#1890FF' } }, - { name: '閫�娆鹃噾棰�', type: 'bar', smooth: true, yAxisIndex: 1, itemStyle: { color: '#00C050' } } - ], - toolbox: { - feature: { - // 鏁版嵁鍖哄煙缂╂斁 - dataZoom: { - yAxisIndex: false // Y杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '鍟嗗搧鐘跺喌' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross' - }, - padding: [5, 10] - }, - xAxis: { - type: 'category', - boundaryGap: true, - axisTick: { - show: false - } - }, - yAxis: [ - { - type: 'value', - name: '閲戦', - axisLine: { - show: false - }, - axisTick: { - show: false - }, - axisLabel: { - textStyle: { - color: '#7F8B9C' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#F5F7F9' - } - } - }, - { - type: 'value', - name: '鏁伴噺', - axisLine: { - show: false - }, - axisTick: { - show: false - }, - axisLabel: { - textStyle: { - color: '#7F8B9C' - } - }, - splitLine: { - show: true, - lineStyle: { - color: '#F5F7F9' - } - } - } - ] -}) as EChartsOption - -/** 澶勭悊鍟嗗搧鐘跺喌鏌ヨ */ -const getProductTrendData = async () => { - trendLoading.value = true - // 1. 澶勭悊鏃堕棿: 寮�濮嬩笌鎴鍦ㄥ悓涓�澶╃殑, 鎶樼嚎鍥惧嚭涓嶆潵, 闇�瑕佸欢闀夸竴澶� - const times = shortcutDateRangePicker.value.times - if (DateUtil.isSameDay(times[0], times[1])) { - // 鍓嶅ぉ - times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd')) - } - // 鏌ヨ鏁版嵁 - await Promise.all([getProductTrendSummary(), getProductStatisticsList()]) - trendLoading.value = false -} - -/** 鏌ヨ鍟嗗搧鐘跺喌鏁版嵁缁熻 */ -const getProductTrendSummary = async () => { - const times = shortcutDateRangePicker.value.times - trendSummary.value = await ProductStatisticsApi.getProductStatisticsAnalyse({ times }) -} - -/** 鏌ヨ鍟嗗搧鐘跺喌鏁版嵁鍒楄〃 */ -const getProductStatisticsList = async () => { - // 鏌ヨ鏁版嵁 - const times = shortcutDateRangePicker.value.times - const list: ProductStatisticsVO[] = await ProductStatisticsApi.getProductStatisticsList({ times }) - // 澶勭悊鏁版嵁 - for (let item of list) { - item.orderPayPrice = fenToYuan(item.orderPayPrice) - item.afterSaleRefundPrice = fenToYuan(item.afterSaleRefundPrice) - } - // 鏇存柊 Echarts 鏁版嵁 - if (lineChartOptions.dataset && lineChartOptions.dataset['source']) { - lineChartOptions.dataset['source'] = list - } -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const times = shortcutDateRangePicker.value.times - const data = await ProductStatisticsApi.exportProductStatisticsExcel({ times }) - download.excel(data, '鍟嗗搧鐘跺喌.xls') - } catch { - } finally { - exportLoading.value = false - } -} -</script> -<style lang="scss" scoped></style> diff --git a/src/views/mall/statistics/product/index.vue b/src/views/mall/statistics/product/index.vue deleted file mode 100644 index d1bcba6..0000000 --- a/src/views/mall/statistics/product/index.vue +++ /dev/null @@ -1,16 +0,0 @@ -<template> - <doc-alert title="銆愮粺璁°�戜細鍛樸�佸晢鍝併�佷氦鏄撶粺璁�" url="https://doc.iocoder.cn/mall/statistics/" /> - - <!-- 鍟嗗搧姒傝 --> - <ProductSummary /> - <!-- 鍟嗗搧鎺掕 --> - <ProductRank class="mt-16px" /> -</template> -<script lang="ts" setup> -import ProductSummary from './components/ProductSummary.vue' -import ProductRank from './components/ProductRank.vue' - -/** 鍟嗗搧缁熻 */ -defineOptions({ name: 'ProductStatistics' }) -</script> -<style lang="scss" scoped></style> diff --git a/src/views/mall/statistics/trade/components/TradeStatisticValue.vue b/src/views/mall/statistics/trade/components/TradeStatisticValue.vue deleted file mode 100644 index 77b8822..0000000 --- a/src/views/mall/statistics/trade/components/TradeStatisticValue.vue +++ /dev/null @@ -1,36 +0,0 @@ -<template> - <div class="flex flex-col gap-2 bg-[var(--el-bg-color-overlay)] p-6"> - <div class="flex items-center justify-between text-gray-500"> - <span>{{ title }}</span> - <el-tooltip :content="tooltip" placement="top-start" v-if="tooltip"> - <Icon icon="ep:warning" /> - </el-tooltip> - </div> - <div class="mb-4 text-3xl"> - <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" /> - </div> - <div class="flex flex-row gap-1 text-sm"> - <span class="text-gray-500">鐜瘮</span> - <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'"> - {{ Math.abs(toNumber(percent)) }}% - <Icon :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" class="!text-sm" /> - </span> - </div> - </div> -</template> -<script lang="ts" setup> -import { propTypes } from '@/utils/propTypes' -import { toNumber } from 'lodash-es' - -/** 浜ゆ槗缁熻鍊肩粍浠� */ -defineOptions({ name: 'TradeStatisticValue' }) - -defineProps({ - tooltip: propTypes.string.def(''), - title: propTypes.string.def(''), - prefix: propTypes.string.def(''), - value: propTypes.number.def(0), - decimals: propTypes.number.def(0), - percent: propTypes.oneOfType([Number, String]).def(0) -}) -</script> diff --git a/src/views/mall/statistics/trade/index.vue b/src/views/mall/statistics/trade/index.vue deleted file mode 100644 index 0a25fd7..0000000 --- a/src/views/mall/statistics/trade/index.vue +++ /dev/null @@ -1,363 +0,0 @@ -<template> - <doc-alert title="銆愮粺璁°�戜細鍛樸�佸晢鍝併�佷氦鏄撶粺璁�" url="https://doc.iocoder.cn/mall/statistics/" /> - - <div class="flex flex-col"> - <el-row :gutter="16" class="summary"> - <el-col :sm="6" :xs="12"> - <TradeStatisticValue - tooltip="鏄ㄦ棩璁㈠崟鏁伴噺" - title="鏄ㄦ棩璁㈠崟鏁伴噺" - :value="summary?.value?.yesterdayOrderCount || 0" - :percent=" - calculateRelativeRate( - summary?.value?.yesterdayOrderCount, - summary?.reference?.yesterdayOrderCount - ) - " - /> - </el-col> - <el-col :sm="6" :xs="12"> - <TradeStatisticValue - tooltip="鏈湀璁㈠崟鏁伴噺" - title="鏈湀璁㈠崟鏁伴噺" - :value="summary?.value?.monthOrderCount || 0" - :percent=" - calculateRelativeRate( - summary?.value?.monthOrderCount, - summary?.reference?.monthOrderCount - ) - " - /> - </el-col> - <el-col :sm="6" :xs="12"> - <TradeStatisticValue - tooltip="鏄ㄦ棩鏀粯閲戦" - title="鏄ㄦ棩鏀粯閲戦" - prefix="锟�" - :decimals="2" - :value="fenToYuan(summary?.value?.yesterdayPayPrice || 0)" - :percent=" - calculateRelativeRate( - summary?.value?.yesterdayPayPrice, - summary?.reference?.yesterdayPayPrice - ) - " - /> - </el-col> - <el-col :sm="6" :xs="12"> - <TradeStatisticValue - tooltip="鏈湀鏀粯閲戦" - title="鏈湀鏀粯閲戦" - prefix="锟�" - ::decimals="2" - :value="fenToYuan(summary?.value?.monthPayPrice || 0)" - :percent=" - calculateRelativeRate(summary?.value?.monthPayPrice, summary?.reference?.monthPayPrice) - " - /> - </el-col> - </el-row> - <el-card shadow="never"> - <template #header> - <!-- 鏍囬 --> - <div class="flex flex-row items-center justify-between"> - <CardTitle title="浜ゆ槗鐘跺喌" /> - <!-- 鏌ヨ鏉′欢 --> - <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getTradeTrendData"> - <el-button - class="ml-4" - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['statistics:trade:export']" - > - <Icon icon="ep:download" class="mr-1" />瀵煎嚭 - </el-button> - </ShortcutDateRangePicker> - </div> - </template> - <!-- 缁熻鍊� --> - <el-row :gutter="16"> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="钀ヤ笟棰�" - tooltip="鍟嗗搧鏀粯閲戦銆佸厖鍊奸噾棰�" - icon="fa-solid:yen-sign" - icon-color="bg-blue-100" - icon-bg-color="text-blue-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.turnoverPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.turnoverPrice, - trendSummary?.reference?.turnoverPrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="鍟嗗搧鏀粯閲戦" - tooltip="鐢ㄦ埛璐拱鍟嗗搧鐨勫疄闄呮敮浠橀噾棰濓紝鍖呮嫭寰俊鏀粯銆佷綑棰濇敮浠樸�佹敮浠樺疂鏀粯銆佺嚎涓嬫敮浠橀噾棰濓紙鎷煎洟鍟嗗搧鍦ㄦ垚鍥箣鍚庤鍏ワ紝绾夸笅鏀粯璁㈠崟鍦ㄥ悗鍙扮‘璁ゆ敮浠樺悗璁″叆锛�" - icon="fa-solid:shopping-cart" - icon-color="bg-purple-100" - icon-bg-color="text-purple-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.orderPayPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.orderPayPrice, - trendSummary?.reference?.orderPayPrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="鍏呭�奸噾棰�" - tooltip="鐢ㄦ埛鎴愬姛鍏呭�肩殑閲戦" - icon="fa-solid:money-check-alt" - icon-color="bg-yellow-100" - icon-bg-color="text-yellow-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.rechargePrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.rechargePrice, - trendSummary?.reference?.rechargePrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="鏀嚭閲戦" - tooltip="浣欓鏀粯閲戦銆佹敮浠樹剑閲戦噾棰濄�佸晢鍝侀��娆鹃噾棰�" - icon="ep:warning-filled" - icon-color="bg-green-100" - icon-bg-color="text-green-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.expensePrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.expensePrice, - trendSummary?.reference?.expensePrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="浣欓鏀粯閲戦" - tooltip="鐢ㄦ埛涓嬪崟鏃朵娇鐢ㄤ綑棰濆疄闄呮敮浠樼殑閲戦" - icon="fa-solid:wallet" - icon-color="bg-cyan-100" - icon-bg-color="text-cyan-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.walletPayPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.walletPayPrice, - trendSummary?.reference?.walletPayPrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="鏀粯浣i噾閲戦" - tooltip="鍚庡彴缁欐帹骞垮憳鏀粯鐨勬帹骞夸剑閲戯紝浠ュ疄闄呮敮浠樹负鍑�" - icon="fa-solid:award" - icon-color="bg-yellow-100" - icon-bg-color="text-yellow-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.brokerageSettlementPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.brokerageSettlementPrice, - trendSummary?.reference?.brokerageSettlementPrice - ) - " - /> - </el-col> - <el-col :md="6" :sm="12" :xs="24"> - <SummaryCard - title="鍟嗗搧閫�娆鹃噾棰�" - tooltip="鐢ㄦ埛鎴愬姛閫�娆剧殑鍟嗗搧閲戦" - icon="fa-solid:times-circle" - icon-color="bg-blue-100" - icon-bg-color="text-blue-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(trendSummary?.value?.afterSaleRefundPrice || 0)" - :percent=" - calculateRelativeRate( - trendSummary?.value?.afterSaleRefundPrice, - trendSummary?.reference?.afterSaleRefundPrice - ) - " - /> - </el-col> - </el-row> - <!-- 鎶樼嚎鍥� --> - <el-skeleton :loading="trendLoading" animated> - <Echart :height="500" :options="lineChartOptions" /> - </el-skeleton> - </el-card> - </div> -</template> -<script lang="ts" setup> -import * as TradeStatisticsApi from '@/api/mall/statistics/trade' -import TradeStatisticValue from './components/TradeStatisticValue.vue' -import SummaryCard from '@/components/SummaryCard/index.vue' -import { EChartsOption } from 'echarts' -import { DataComparisonRespVO } from '@/api/mall/statistics/common' -import { TradeSummaryRespVO, TradeTrendSummaryRespVO } from '@/api/mall/statistics/trade' -import { calculateRelativeRate, fenToYuan } from '@/utils' -import download from '@/utils/download' -import { CardTitle } from '@/components/Card' -import * as DateUtil from '@/utils/formatTime' -import dayjs from 'dayjs' - -/** 浜ゆ槗缁熻 */ -defineOptions({ name: 'TradeStatistics' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const trendLoading = ref(true) // 浜ゆ槗鐘舵�佸姞杞戒腑 -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 -const summary = ref<DataComparisonRespVO<TradeSummaryRespVO>>() // 浜ゆ槗缁熻鏁版嵁 -const trendSummary = ref<DataComparisonRespVO<TradeTrendSummaryRespVO>>() // 浜ゆ槗鐘跺喌缁熻鏁版嵁 -const shortcutDateRangePicker = ref() - -/** 鎶樼嚎鍥鹃厤缃� */ -const lineChartOptions = reactive<EChartsOption>({ - dataset: { - dimensions: ['date', 'turnoverPrice', 'orderPayPrice', 'rechargePrice', 'expensePrice'], - source: [] - }, - grid: { - left: 20, - right: 20, - bottom: 20, - top: 80, - containLabel: true - }, - legend: { - top: 50 - }, - series: [ - { name: '钀ヤ笟棰�', type: 'line', smooth: true }, - { name: '鍟嗗搧鏀粯閲戦', type: 'line', smooth: true }, - { name: '鍏呭�奸噾棰�', type: 'line', smooth: true }, - { name: '鏀嚭閲戦', type: 'line', smooth: true } - ], - toolbox: { - feature: { - // 鏁版嵁鍖哄煙缂╂斁 - dataZoom: { - yAxisIndex: false // Y杞翠笉缂╂斁 - }, - brush: { - type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽� - }, - saveAsImage: { show: true, name: '浜ゆ槗鐘跺喌' } // 淇濆瓨涓哄浘鐗� - } - }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross' - }, - padding: [5, 10] - }, - xAxis: { - type: 'category', - boundaryGap: false, - axisTick: { - show: false - } - }, - yAxis: { - axisTick: { - show: false - } - } -}) as EChartsOption - -/** 澶勭悊浜ゆ槗鐘跺喌鏌ヨ */ -const getTradeTrendData = async () => { - trendLoading.value = true - // 1. 澶勭悊鏃堕棿: 寮�濮嬩笌鎴鍦ㄥ悓涓�澶╃殑, 鎶樼嚎鍥惧嚭涓嶆潵, 闇�瑕佸欢闀夸竴澶� - const times = shortcutDateRangePicker.value.times - if (DateUtil.isSameDay(times[0], times[1])) { - // 鍓嶅ぉ - times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd')) - } - // 鏌ヨ鏁版嵁 - await Promise.all([getTradeStatisticsAnalyse(), getTradeStatisticsList()]) - trendLoading.value = false -} - -/** 鏌ヨ浜ゆ槗缁熻 */ -const getTradeStatisticsSummary = async () => { - summary.value = await TradeStatisticsApi.getTradeStatisticsSummary() -} - -/** 鏌ヨ浜ゆ槗鐘跺喌鏁版嵁缁熻 */ -const getTradeStatisticsAnalyse = async () => { - const times = shortcutDateRangePicker.value.times - trendSummary.value = await TradeStatisticsApi.getTradeStatisticsAnalyse({ times }) -} - -/** 鏌ヨ浜ゆ槗鐘跺喌鏁版嵁鍒楄〃 */ -const getTradeStatisticsList = async () => { - // 鏌ヨ鏁版嵁 - const times = shortcutDateRangePicker.value.times - const list = await TradeStatisticsApi.getTradeStatisticsList({ times }) - // 澶勭悊鏁版嵁 - for (let item of list) { - item.turnoverPrice = fenToYuan(item.turnoverPrice) - item.orderPayPrice = fenToYuan(item.orderPayPrice) - item.rechargePrice = fenToYuan(item.rechargePrice) - item.expensePrice = fenToYuan(item.expensePrice) - } - // 鏇存柊 Echarts 鏁版嵁 - if (lineChartOptions.dataset && lineChartOptions.dataset['source']) { - lineChartOptions.dataset['source'] = list - } -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const times = shortcutDateRangePicker.value.times - const data = await TradeStatisticsApi.exportTradeStatisticsExcel({ times }) - download.excel(data, '浜ゆ槗鐘跺喌.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getTradeStatisticsSummary() -}) -</script> -<style lang="scss" scoped> -.summary { - .el-col { - margin-bottom: 1rem; - } -} -</style> diff --git a/src/views/mall/trade/afterSale/detail/index.vue b/src/views/mall/trade/afterSale/detail/index.vue deleted file mode 100644 index 26df0d3..0000000 --- a/src/views/mall/trade/afterSale/detail/index.vue +++ /dev/null @@ -1,354 +0,0 @@ -<template> - <ContentWrap> - <!-- 璁㈠崟淇℃伅 --> - <el-descriptions title="璁㈠崟淇℃伅"> - <el-descriptions-item label="璁㈠崟鍙�: ">{{ formData.orderNo }}</el-descriptions-item> - <el-descriptions-item label="閰嶉�佹柟寮�: "> - <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="formData.order.deliveryType" /> - </el-descriptions-item> - <el-descriptions-item label="璁㈠崟绫诲瀷: "> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="formData.order.type" /> - </el-descriptions-item> - <el-descriptions-item label="鏀惰揣浜�: "> - {{ formData.order.receiverName }} - </el-descriptions-item> - <el-descriptions-item label="涔板鐣欒█: "> - {{ formData.order.userRemark }} - </el-descriptions-item> - <el-descriptions-item label="璁㈠崟鏉ユ簮: "> - <dict-tag :type="DICT_TYPE.TERMINAL" :value="formData.order.terminal" /> - </el-descriptions-item> - <el-descriptions-item label="鑱旂郴鐢佃瘽: "> - {{ formData.order.receiverMobile }} - </el-descriptions-item> - <el-descriptions-item label="鍟嗗澶囨敞: ">{{ formData.order.remark }}</el-descriptions-item> - <el-descriptions-item label="鏀粯鍗曞彿: "> - {{ formData.order.payOrderId }} - </el-descriptions-item> - <el-descriptions-item label="浠樻鏂瑰紡: "> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="formData.order.payChannelCode" /> - </el-descriptions-item> - <el-descriptions-item label="涔板: ">{{ formData?.user?.nickname }}</el-descriptions-item> - </el-descriptions> - - <!-- 鍞悗淇℃伅 --> - <el-descriptions title="鍞悗淇℃伅"> - <el-descriptions-item label="閫�娆剧紪鍙�: ">{{ formData.no }}</el-descriptions-item> - <el-descriptions-item label="鐢宠鏃堕棿: "> - {{ formatDate(formData.auditTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍞悗绫诲瀷: "> - <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_TYPE" :value="formData.type" /> - </el-descriptions-item> - <el-descriptions-item label="鍞悗鏂瑰紡: "> - <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_WAY" :value="formData.way" /> - </el-descriptions-item> - <el-descriptions-item label="閫�娆鹃噾棰�: "> - {{ fenToYuan(formData.refundPrice) }} - </el-descriptions-item> - <el-descriptions-item label="閫�娆惧師鍥�: ">{{ formData.applyReason }}</el-descriptions-item> - <el-descriptions-item label="琛ュ厖鎻忚堪: "> - {{ formData.applyDescription }} - </el-descriptions-item> - <el-descriptions-item label="鍑瘉鍥剧墖: "> - <el-image - v-for="(item, index) in formData.applyPicUrls" - :key="index" - :src="item.url" - class="mr-10px h-60px w-60px" - @click="imagePreview(formData.applyPicUrls)" - /> - </el-descriptions-item> - </el-descriptions> - - <!-- 閫�娆剧姸鎬� --> - <el-descriptions :column="1" title="閫�娆剧姸鎬�"> - <el-descriptions-item label="閫�娆剧姸鎬�: "> - <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_STATUS" :value="formData.status" /> - </el-descriptions-item> - <el-descriptions-item label-class-name="no-colon"> - <el-button v-if="formData.status === 10" type="primary" @click="agree">鍚屾剰鍞悗</el-button> - <el-button v-if="formData.status === 10" type="primary" @click="disagree"> - 鎷掔粷鍞悗 - </el-button> - <el-button v-if="formData.status === 30" type="primary" @click="receive"> - 纭鏀惰揣 - </el-button> - <el-button v-if="formData.status === 30" type="primary" @click="refuse">鎷掔粷鏀惰揣</el-button> - <el-button v-if="formData.status === 40" type="primary" @click="refund">纭閫�娆�</el-button> - </el-descriptions-item> - <el-descriptions-item> - <template #label><span style="color: red">鎻愰啋: </span></template> - 濡傛灉鏈彂璐э紝璇风偣鍑诲悓鎰忛��娆剧粰涔板銆�<br /> - 濡傛灉瀹為檯宸插彂璐э紝璇蜂富鍔ㄤ笌涔板鑱旂郴銆�<br /> - 濡傛灉璁㈠崟鏁翠綋閫�娆惧悗锛屼紭鎯犲埜鍜屼綑棰濅細閫�杩樼粰涔板. - </el-descriptions-item> - </el-descriptions> - - <!-- 鍟嗗搧淇℃伅 --> - <el-descriptions title="鍟嗗搧淇℃伅"> - <el-descriptions-item labelClassName="no-colon"> - <el-row :gutter="20"> - <el-col :span="15"> - <el-table :data="[formData.orderItem]" border> - <el-table-column label="鍟嗗搧" prop="spuName" width="auto"> - <template #default="{ row }"> - {{ row.spuName }} - <el-tag v-for="property in row.properties" :key="property.propertyId"> - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍘熶环" prop="price" width="150"> - <template #default="{ row }">{{ fenToYuan(row.price) }} 鍏�</template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" width="100" /> - <el-table-column label="鍚堣" prop="payPrice" width="150"> - <template #default="{ row }">{{ fenToYuan(row.payPrice) }} 鍏�</template> - </el-table-column> - </el-table> - </el-col> - <el-col :span="10" /> - </el-row> - </el-descriptions-item> - </el-descriptions> - - <!-- 鎿嶄綔鏃ュ織 --> - <el-descriptions title="鍞悗鏃ュ織"> - <el-descriptions-item labelClassName="no-colon"> - <el-timeline> - <el-timeline-item - v-for="saleLog in formData.logs" - :key="saleLog.id" - :timestamp="formatDate(saleLog.createTime)" - placement="top" - > - <div class="el-timeline-right-content"> - <span>{{ saleLog.content }}</span> - </div> - <template #dot> - <span - :style="{ backgroundColor: getUserTypeColor(saleLog.userType) }" - class="dot-node-style" - > - {{ getDictLabel(DICT_TYPE.USER_TYPE, saleLog.userType)[0] || '绯�' }} - </span> - </template> - </el-timeline-item> - </el-timeline> - </el-descriptions-item> - </el-descriptions> - </ContentWrap> - - <!-- 鍚勭鎿嶄綔鐨勫脊绐� --> - <UpdateAuditReasonForm ref="updateAuditReasonFormRef" @success="getDetail" /> -</template> -<script lang="ts" setup> -import * as AfterSaleApi from '@/api/mall/trade/afterSale/index' -import { fenToYuan } from '@/utils' -import { DICT_TYPE, getDictLabel, getDictObj } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import UpdateAuditReasonForm from '@/views/mall/trade/afterSale/form/AfterSaleDisagreeForm.vue' -import { createImageViewer } from '@/components/ImageViewer' -import { isArray } from '@/utils/is' -import { useTagsViewStore } from '@/store/modules/tagsView' - -defineOptions({ name: 'TradeAfterSaleDetail' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const { params } = useRoute() // 鏌ヨ鍙傛暟 -const { push, currentRoute } = useRouter() // 璺敱 -const formData = ref({ - order: {}, - logs: [] -}) -const updateAuditReasonFormRef = ref() // 鎷掔粷鍞悗琛ㄥ崟 Ref - -/** 鑾峰緱 userType 棰滆壊 */ -const getUserTypeColor = (type: number) => { - const dict = getDictObj(DICT_TYPE.USER_TYPE, type) - switch (dict?.colorType) { - case 'success': - return '#67C23A' - case 'info': - return '#909399' - case 'warning': - return '#E6A23C' - case 'danger': - return '#F56C6C' - } - return '#409EFF' -} - -/** 鑾峰緱璇︽儏 */ -const getDetail = async () => { - const id = params.id as unknown as number - if (id) { - const res = await AfterSaleApi.getAfterSale(id) - // 娌℃湁琛ㄥ崟淇℃伅鍒欏叧闂〉闈㈣繑鍥� - if (res == null) { - message.notifyError('鍞悗璁㈠崟涓嶅瓨鍦�') - close() - } - formData.value = res - } -} - -/** 鍚屾剰鍞悗 */ -const agree = async () => { - try { - // 浜屾纭 - await message.confirm('鏄惁鍚屾剰鍞悗锛�') - await AfterSaleApi.agree(formData.value.id) - // 鎻愮ず鎴愬姛 - message.success(t('common.success')) - await getDetail() - } catch {} -} - -/** 鎷掔粷鍞悗 */ -const disagree = async () => { - updateAuditReasonFormRef.value?.open(formData.value) -} - -/** 纭鏀惰揣 */ -const receive = async () => { - try { - // 浜屾纭 - await message.confirm('鏄惁纭鏀惰揣锛�') - await AfterSaleApi.receive(formData.value.id) - // 鎻愮ず鎴愬姛 - message.success(t('common.success')) - await getDetail() - } catch {} -} - -/** 鎷掔粷鏀惰揣 */ -const refuse = async () => { - try { - // 浜屾纭 - await message.confirm('鏄惁鎷掔粷鏀惰揣锛�') - await AfterSaleApi.refuse(formData.value.id) - // 鎻愮ず鎴愬姛 - message.success(t('common.success')) - await getDetail() - } catch {} -} - -/** 纭閫�娆� */ -const refund = async () => { - try { - // 浜屾纭 - await message.confirm('鏄惁纭閫�娆撅紵') - await AfterSaleApi.refund(formData.value.id) - // 鎻愮ず鎴愬姛 - message.success(t('common.success')) - await getDetail() - } catch {} -} - -/** 鍥剧墖棰勮 */ -const imagePreview = (args) => { - const urlList = [] - if (isArray(args)) { - args.forEach((item) => { - urlList.push(item.url) - }) - } else { - urlList.push(args) - } - createImageViewer({ - urlList - }) -} -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -/** 鍏抽棴 tag */ -const close = () => { - delView(unref(currentRoute)) - push({ name: 'TradeAfterSale' }) -} -onMounted(async () => { - await getDetail() -}) -</script> -<style lang="scss" scoped> -:deep(.el-descriptions) { - &:not(:nth-child(1)) { - margin-top: 20px; - } - - .el-descriptions__title { - display: flex; - align-items: center; - - &::before { - display: inline-block; - width: 3px; - height: 20px; - margin-right: 10px; - background-color: #409eff; - content: ''; - } - } - - .el-descriptions-item__container { - margin: 0 10px; - - .no-colon { - margin: 0; - - &::after { - content: ''; - } - } - } -} - -// 鏃堕棿绾挎牱寮忚皟鏁� -:deep(.el-timeline) { - margin: 10px 0 0 160px; - - .el-timeline-item__wrapper { - position: relative; - top: -20px; - - .el-timeline-item__timestamp { - position: absolute !important; - top: 10px; - left: -150px; - } - } - - .el-timeline-right-content { - display: flex; - align-items: center; - min-height: 30px; - padding: 10px; - background-color: #f7f8fa; - - &::before { - position: absolute; - top: 10px; - left: 13px; - border-color: transparent #f7f8fa transparent transparent; /* 灏栬棰滆壊锛屽乏渚ф湞鍚� */ - border-style: solid; - border-width: 8px; /* 璋冩暣灏栬澶у皬 */ - content: ''; - } - } - - .dot-node-style { - position: absolute; - left: -5px; - display: flex; - width: 20px; - height: 20px; - font-size: 10px; - color: #fff; - border-radius: 50%; - justify-content: center; - align-items: center; - } -} -</style> diff --git a/src/views/mall/trade/afterSale/form/AfterSaleDisagreeForm.vue b/src/views/mall/trade/afterSale/form/AfterSaleDisagreeForm.vue deleted file mode 100644 index af3ab35..0000000 --- a/src/views/mall/trade/afterSale/form/AfterSaleDisagreeForm.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鎷掔粷鍞悗" width="45%"> - <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px"> - <el-form-item label="瀹℃壒澶囨敞"> - <el-input - v-model="formData.auditReason" - :rows="3" - placeholder="璇疯緭鍏ュ鎵瑰娉�" - type="textarea" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as AfterSaleApi from '@/api/mall/trade/afterSale/index' - -defineOptions({ name: 'AfterSaleDisagreeForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, // 鍞悗璁㈠崟缂栧彿 - auditReason: '' // 瀹℃壒澶囨敞 -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (row: AfterSaleApi.TradeAfterSaleVO) => { - resetForm() - // 璁剧疆鏁版嵁 - formData.value.id = row.id - formData.value.auditReason = row.auditReason - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = unref(formData) - await AfterSaleApi.disagree(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, // 鍞悗璁㈠崟缂栧彿 - auditReason: '' // 瀹℃壒澶囨敞 - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/trade/afterSale/index.vue b/src/views/mall/trade/afterSale/index.vue deleted file mode 100644 index 52051c3..0000000 --- a/src/views/mall/trade/afterSale/index.vue +++ /dev/null @@ -1,269 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝敭鍚庨��娆�" url="https://doc.iocoder.cn/mall/trade-aftersale/" /> - - <!-- 鎼滅储 --> - <ContentWrap> - <el-form ref="queryFormRef" :inline="true" :model="queryParams" label-width="68px"> - <el-form-item label="鍟嗗搧鍚嶇О" prop="spuName"> - <el-input - v-model="queryParams.spuName" - class="!w-280px" - clearable - placeholder="璇疯緭鍏ュ晢鍝� SPU 鍚嶇О" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="閫�娆剧紪鍙�" prop="no"> - <el-input - v-model="queryParams.no" - class="!w-280px" - clearable - placeholder="璇疯緭鍏ラ��娆剧紪鍙�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="璁㈠崟缂栧彿" prop="orderNo"> - <el-input - v-model="queryParams.orderNo" - class="!w-280px" - clearable - placeholder="璇疯緭鍏ヨ鍗曠紪鍙�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鍞悗鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - class="!w-280px" - clearable - placeholder="璇烽�夋嫨鍞悗鐘舵��" - > - <el-option label="鍏ㄩ儴" value="0" /> - <el-option - v-for="dict in getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍞悗鏂瑰紡" prop="way"> - <el-select - v-model="queryParams.way" - class="!w-280px" - clearable - placeholder="璇烽�夋嫨鍞悗鏂瑰紡" - > - <el-option - v-for="dict in getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_WAY)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍞悗绫诲瀷" prop="type"> - <el-select - v-model="queryParams.type" - class="!w-280px" - clearable - placeholder="璇烽�夋嫨鍞悗绫诲瀷" - > - <el-option - v-for="dict in getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-260px" - end-placeholder="鑷畾涔夋椂闂�" - start-placeholder="鑷畾涔夋椂闂�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <el-tabs v-model="queryParams.status" @tab-click="tabClick"> - <el-tab-pane - v-for="item in statusTabs" - :key="item.label" - :label="item.label" - :name="item.value" - /> - </el-tabs> - <!-- 鍒楄〃 --> - <el-table v-loading="loading" :data="list"> - <el-table-column align="center" label="閫�娆剧紪鍙�" min-width="200" prop="no" /> - <el-table-column align="center" label="璁㈠崟缂栧彿" min-width="200" prop="orderNo"> - <template #default="{ row }"> - <el-button link type="primary" @click="openOrderDetail(row.orderId)"> - {{ row.orderNo }} - </el-button> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧淇℃伅" min-width="600" prop="spuName"> - <template #default="{ row }"> - <div class="flex items-center"> - <el-image - :src="row.picUrl" - class="mr-10px h-30px w-30px" - @click="imagePreview(row.picUrl)" - /> - <span class="mr-10px">{{ row.spuName }}</span> - <el-tag v-for="property in row.properties" :key="property.propertyId" class="mr-10px"> - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </div> - </template> - </el-table-column> - <el-table-column align="center" label="璁㈠崟閲戦" prop="refundPrice"> - <template #default="scope"> - <span>{{ fenToYuan(scope.row.refundPrice) }} 鍏�</span> - </template> - </el-table-column> - <el-table-column align="center" label="涔板" prop="user.nickname" /> - <el-table-column align="center" label="鐢宠鏃堕棿" prop="createTime" width="180"> - <template #default="scope"> - <span>{{ formatDate(scope.row.createTime) }}</span> - </template> - </el-table-column> - <el-table-column align="center" label="鍞悗鐘舵��" width="100"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" label="鍞悗鏂瑰紡"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_WAY" :value="scope.row.way" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="160"> - <template #default="{ row }"> - <el-button link type="primary" @click="openAfterSaleDetail(row.id)">澶勭悊閫�娆�</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as AfterSaleApi from '@/api/mall/trade/afterSale/index' -import { DICT_TYPE, getDictOptions } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import { createImageViewer } from '@/components/ImageViewer' -import { TabsPaneContext } from 'element-plus' -import { cloneDeep } from 'lodash-es' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'TradeAfterSale' }) - -const { push } = useRouter() // 璺敱璺宠浆 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<AfterSaleApi.TradeAfterSaleVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const statusTabs = ref([ - { - label: '鍏ㄩ儴', - value: '0' - } -]) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -// 鏌ヨ鍙傛暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: null, - status: '0', - orderNo: null, - spuName: null, - createTime: [], - way: null, - type: null -}) -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = cloneDeep(queryParams) - // 澶勭悊鎺夊叏閮ㄧ殑鐘舵�侊紝涓嶄紶灏辨槸鍏ㄩ儴 - if (data.status === '0') { - delete data.status - } - // 鎵ц鏌ヨ - const res = (await AfterSaleApi.getAfterSalePage(data)) as AfterSaleApi.TradeAfterSaleVO[] - list.value = res.list - total.value = res.total - } finally { - loading.value = false - } -} -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = async () => { - queryParams.pageNo = 1 - await getList() -} -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} -/** tab 鍒囨崲 */ -const tabClick = async (tab: TabsPaneContext) => { - queryParams.status = tab.paneName - await getList() -} - -/** 澶勭悊閫�娆� */ -const openAfterSaleDetail = (id: number) => { - push({ name: 'TradeAfterSaleDetail', params: { id } }) -} - -/** 鏌ョ湅璁㈠崟璇︽儏 */ -const openOrderDetail = (id: number) => { - push({ name: 'TradeOrderDetail', params: { id } }) -} - -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} - -onMounted(async () => { - await getList() - // 璁剧疆 statuses 杩囨护 - for (const dict of getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_STATUS)) { - statusTabs.value.push({ - label: dict.label, - value: dict.value - }) - } -}) -</script> diff --git a/src/views/mall/trade/brokerage/record/index.vue b/src/views/mall/trade/brokerage/record/index.vue deleted file mode 100644 index 8f138ad..0000000 --- a/src/views/mall/trade/brokerage/record/index.vue +++ /dev/null @@ -1,171 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝垎閿�杩斾剑" url="https://doc.iocoder.cn/mall/trade-brokerage/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-input - v-model="queryParams.userId" - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="涓氬姟绫诲瀷" prop="bizType"> - <el-select - v-model="queryParams.bizType" - placeholder="璇烽�夋嫨涓氬姟绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_RECORD_BIZ_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_RECORD_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" min-width="60" /> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="userId" min-width="80" /> - <el-table-column label="澶村儚" align="center" prop="userAvatar" width="70px"> - <template #default="scope"> - <el-avatar :src="scope.row.userAvatar" /> - </template> - </el-table-column> - <el-table-column label="鏄电О" align="center" prop="userNickname" min-width="80px" /> - <el-table-column label="涓氬姟绫诲瀷" align="center" prop="bizType" min-width="85"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BROKERAGE_RECORD_BIZ_TYPE" :value="scope.row.bizType" /> - </template> - </el-table-column> - <el-table-column label="涓氬姟缂栧彿" align="center" prop="bizId" min-width="80" /> - <el-table-column label="鏍囬" align="center" prop="title" min-width="110" /> - <el-table-column - label="閲戦" - align="center" - prop="price" - min-width="60" - :formatter="fenToYuanFormat" - /> - <el-table-column label="璇存槑" align="center" prop="description" min-width="120" /> - <el-table-column label="鐘舵��" align="center" prop="status" min-width="85"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BROKERAGE_RECORD_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="瑙e喕鏃堕棿" - align="center" - prop="unfreezeTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as BrokerageRecordApi from '@/api/mall/trade/brokerage/record' -import { fenToYuanFormat } from '@/utils/formatter' - -defineOptions({ name: 'TradeBrokerageRecord' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: null, - bizType: null, - price: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BrokerageRecordApi.getBrokerageRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/brokerage/user/BrokerageOrderListDialog.vue b/src/views/mall/trade/brokerage/user/BrokerageOrderListDialog.vue deleted file mode 100644 index 54e3c16..0000000 --- a/src/views/mall/trade/brokerage/user/BrokerageOrderListDialog.vue +++ /dev/null @@ -1,152 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鎺ㄥ箍浜哄垪琛�" width="75%"> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="85px" - > - <el-form-item label="鐢ㄦ埛绫诲瀷" prop="level"> - <el-radio-group v-model="queryParams.level" @change="handleQuery"> - <el-radio-button checked>鍏ㄩ儴</el-radio-button> - <el-radio-button label="1">涓�绾ф帹骞夸汉</el-radio-button> - <el-radio-button label="2">浜岀骇鎺ㄥ箍浜�</el-radio-button> - </el-radio-group> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_RECORD_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="缁戝畾鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="璁㈠崟缂栧彿" align="center" prop="bizId" min-width="80px" /> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="sourceUserId" min-width="80px" /> - <el-table-column label="澶村儚" align="center" prop="sourceUserAvatar" width="70px"> - <template #default="scope"> - <el-avatar :src="scope.row.sourceUserAvatar" /> - </template> - </el-table-column> - <el-table-column label="鏄电О" align="center" prop="sourceUserNickname" min-width="80px" /> - <el-table-column - label="浣i噾" - align="center" - prop="price" - min-width="100px" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鐘舵��" align="center" prop="status" min-width="85"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BROKERAGE_RECORD_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - </Dialog> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as BrokerageRecordApi from '@/api/mall/trade/brokerage/record' -import { BrokerageRecordBizTypeEnum } from '@/utils/constants' -import { fenToYuanFormat } from '@/utils/formatter' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -/** 鎺ㄥ箍璁㈠崟鍒楄〃 */ -defineOptions({ name: 'BrokerageOrderListDialog' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: null, - bizType: BrokerageRecordBizTypeEnum.ORDER.type, - level: '', - createTime: [], - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鎵撳紑寮圭獥 */ -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const open = async (userId: any) => { - dialogVisible.value = true - queryParams.userId = userId - resetQuery() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BrokerageRecordApi.getBrokerageRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} -</script> diff --git a/src/views/mall/trade/brokerage/user/BrokerageUserListDialog.vue b/src/views/mall/trade/brokerage/user/BrokerageUserListDialog.vue deleted file mode 100644 index 87dc8f6..0000000 --- a/src/views/mall/trade/brokerage/user/BrokerageUserListDialog.vue +++ /dev/null @@ -1,137 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鎺ㄥ箍浜哄垪琛�" width="75%"> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="85px" - > - <el-form-item label="鐢ㄦ埛绫诲瀷" prop="level"> - <el-radio-group v-model="queryParams.level" @change="handleQuery"> - <el-radio-button checked>鍏ㄩ儴</el-radio-button> - <el-radio-button label="1">涓�绾ф帹骞夸汉</el-radio-button> - <el-radio-button label="2">浜岀骇鎺ㄥ箍浜�</el-radio-button> - </el-radio-group> - </el-form-item> - <el-form-item label="缁戝畾鏃堕棿" prop="bindUserTime"> - <el-date-picker - v-model="queryParams.bindUserTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="id" min-width="80px" /> - <el-table-column label="澶村儚" align="center" prop="avatar" width="70px"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column label="鏄电О" align="center" prop="nickname" min-width="80px" /> - <el-table-column - label="鎺ㄥ箍浜烘暟" - align="center" - prop="brokerageUserCount" - min-width="80px" - /> - <el-table-column - label="鎺ㄥ箍璁㈠崟鏁伴噺" - align="center" - prop="brokerageOrderCount" - min-width="110px" - /> - <el-table-column label="鎺ㄥ箍璧勬牸" align="center" prop="brokerageEnabled" min-width="80px"> - <template #default="scope"> - <el-tag v-if="scope.row.brokerageEnabled">鏈�</el-tag> - <el-tag v-else type="info">鏃�</el-tag> - </template> - </el-table-column> - <el-table-column - label="缁戝畾鏃堕棿" - align="center" - prop="bindUserTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - </Dialog> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as BrokerageUserApi from '@/api/mall/trade/brokerage/user' - -/** 鎺ㄥ箍浜哄垪琛� */ -defineOptions({ name: 'BrokerageUserListDialog' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - bindUserId: null, - level: '', - bindUserTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鎵撳紑寮圭獥 */ -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const open = async (bindUserId: any) => { - dialogVisible.value = true - queryParams.bindUserId = bindUserId - resetQuery() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BrokerageUserApi.getBrokerageUserPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} -</script> diff --git a/src/views/mall/trade/brokerage/user/UpdateBindUserForm.vue b/src/views/mall/trade/brokerage/user/UpdateBindUserForm.vue deleted file mode 100644 index 77ffac7..0000000 --- a/src/views/mall/trade/brokerage/user/UpdateBindUserForm.vue +++ /dev/null @@ -1,127 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="淇敼涓婄骇鎺ㄥ箍浜�" width="500"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - > - <el-form-item label="鎺ㄥ箍浜�" prop="bindUserId"> - <el-input - v-model="formData.bindUserId" - placeholder="璇疯緭鍏ユ帹骞垮憳缂栧彿" - v-loading="formLoading" - > - <template #append> - <el-button @click="handleGetUser"><Icon icon="ep:search" class="mr-5px" /></el-button> - </template> - </el-input> - </el-form-item> - </el-form> - <!-- 灞曠ず涓婄骇鎺ㄥ箍浜虹殑淇℃伅 --> - <el-descriptions v-if="bindUser" :column="1" border> - <el-descriptions-item label="澶村儚"> - <el-avatar :src="bindUser.avatar" /> - </el-descriptions-item> - <el-descriptions-item label="鏄电О">{{ bindUser.nickname }}</el-descriptions-item> - <el-descriptions-item label="鎺ㄥ箍璧勬牸"> - <el-tag v-if="bindUser.brokerageEnabled">鏈�</el-tag> - <el-tag v-else type="info">鏃�</el-tag> - </el-descriptions-item> - <el-descriptions-item label="鎴愪负鎺ㄥ箍鍛樼殑鏃堕棿"> - {{ formatDate(bindUser.brokerageTime) }} - </el-descriptions-item> - </el-descriptions> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as BrokerageUserApi from '@/api/mall/trade/brokerage/user' -import { formatDate } from '@/utils/formatTime' - -/** 淇敼涓婄骇鎺ㄥ箍浜鸿〃鍗� */ -defineOptions({ name: 'UpdateBindUserForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref() -const formRef = ref() // 琛ㄥ崟 Ref -const formRules = reactive({ - bindUserId: [{ required: true, message: '鎺ㄥ箍鍛樹汉涓嶈兘涓虹┖', trigger: 'blur' }] -}) - -/** 鎵撳紑寮圭獥 */ -const open = async (row: BrokerageUserApi.BrokerageUserVO) => { - resetForm() - // 璁剧疆鏁版嵁 - formData.value.id = row.id - formData.value.bindUserId = row.bindUserId - // 鍙嶆樉涓婄骇鎺ㄥ箍浜� - if (row.bindUserId) { - await handleGetUser() - } - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -/** 淇敼涓婄骇鎺ㄥ箍浜� */ -const submitForm = async () => { - if (formLoading.value) return - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鏈煡鎵惧埌鍚堥�傜殑涓婄骇 - if (!bindUser.value) { - message.error('璇峰厛鏌ヨ骞剁‘璁ゆ帹骞夸汉') - return - } - - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - // 鍙戣捣淇敼 - await BrokerageUserApi.updateBindUser(formData.value) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - bindUserId: undefined - } - formRef.value?.resetFields() - bindUser.value = undefined -} - -/** 鏌ヨ鎺ㄥ箍鍛� */ -const bindUser = ref<BrokerageUserApi.BrokerageUserVO>() -const handleGetUser = async () => { - if (formData.value.bindUserId == formData.value.id) { - message.error('涓嶈兘缁戝畾鑷繁涓烘帹骞夸汉') - return - } - formLoading.value = true - bindUser.value = await BrokerageUserApi.getBrokerageUser(formData.value.bindUserId) - if (!bindUser.value) { - message.warning('鎺ㄥ箍鍛樹笉瀛樺湪') - } - formLoading.value = false -} -</script> diff --git a/src/views/mall/trade/brokerage/user/index.vue b/src/views/mall/trade/brokerage/user/index.vue deleted file mode 100644 index 22daf1b..0000000 --- a/src/views/mall/trade/brokerage/user/index.vue +++ /dev/null @@ -1,307 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝垎閿�杩斾剑" url="https://doc.iocoder.cn/mall/trade-brokerage/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="85px" - > - <el-form-item label="鎺ㄥ箍鍛樼紪鍙�" prop="bindUserId"> - <el-input - v-model="queryParams.bindUserId" - placeholder="璇疯緭鍏ユ帹骞垮憳缂栧彿" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎺ㄥ箍璧勬牸" prop="brokerageEnabled"> - <el-select - v-model="queryParams.brokerageEnabled" - class="!w-240px" - clearable - placeholder="璇烽�夋嫨鎺ㄥ箍璧勬牸" - > - <el-option label="鏈�" :value="true" /> - <el-option label="鏃�" :value="false" /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="id" min-width="80px" /> - <el-table-column label="澶村儚" align="center" prop="avatar" width="70px"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column label="鏄电О" align="center" prop="nickname" min-width="80px" /> - <el-table-column label="鎺ㄥ箍浜烘暟" align="center" prop="brokerageUserCount" width="80px" /> - <el-table-column - label="鎺ㄥ箍璁㈠崟鏁伴噺" - align="center" - prop="brokerageOrderCount" - min-width="110px" - /> - <el-table-column - label="鎺ㄥ箍璁㈠崟閲戦" - align="center" - prop="brokerageOrderPrice" - min-width="110px" - :formatter="fenToYuanFormat" - /> - <el-table-column - label="宸叉彁鐜伴噾棰�" - align="center" - prop="withdrawPrice" - min-width="100px" - :formatter="fenToYuanFormat" - /> - <el-table-column label="宸叉彁鐜版鏁�" align="center" prop="withdrawCount" min-width="100px" /> - <el-table-column - label="鏈彁鐜伴噾棰�" - align="center" - prop="price" - min-width="100px" - :formatter="fenToYuanFormat" - /> - <el-table-column - label="鍐荤粨涓剑閲�" - align="center" - prop="frozenPrice" - min-width="100px" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鎺ㄥ箍璧勬牸" align="center" prop="brokerageEnabled" min-width="80px"> - <template #default="scope"> - <el-switch - v-model="scope.row.brokerageEnabled" - active-text="鏈�" - inactive-text="鏃�" - inline-prompt - :disabled="!checkPermi(['trade:brokerage-user:update-bind-user'])" - @change="handleBrokerageEnabledChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column - label="鎴愪负鎺ㄥ箍鍛樻椂闂�" - align="center" - prop="brokerageTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="涓婄骇鎺ㄥ箍鍛樼紪鍙�" align="center" prop="bindUserId" width="150px" /> - <el-table-column - label="鎺ㄥ箍鍛樼粦瀹氭椂闂�" - align="center" - prop="bindUserTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px" fixed="right"> - <template #default="scope"> - <el-dropdown - @command="(command) => handleCommand(command, scope.row)" - v-hasPermi="[ - 'trade:brokerage-user:user-query', - 'trade:brokerage-user:order-query', - 'trade:brokerage-user:update-bind-user', - 'trade:brokerage-user:clear-bind-user' - ]" - > - <el-button link type="primary"> - <Icon icon="ep:d-arrow-right" /> - 鏇村 - </el-button> - <template #dropdown> - <el-dropdown-menu> - <el-dropdown-item - command="openBrokerageUserTable" - v-if="checkPermi(['trade:brokerage-user:user-query'])" - > - 鎺ㄥ箍浜� - </el-dropdown-item> - <el-dropdown-item - command="openBrokerageOrderTable" - v-if="checkPermi(['trade:brokerage-user:order-query'])" - > - 鎺ㄥ箍璁㈠崟 - </el-dropdown-item> - <el-dropdown-item - command="openUpdateBindUserForm" - v-if="checkPermi(['trade:brokerage-user:update-bind-user'])" - > - 淇敼涓婄骇鎺ㄥ箍浜� - </el-dropdown-item> - <el-dropdown-item - command="handleClearBindUser" - v-if=" - scope.row.bindUserId && checkPermi(['trade:brokerage-user:clear-bind-user']) - " - > - 娓呴櫎涓婄骇鎺ㄥ箍浜� - </el-dropdown-item> - </el-dropdown-menu> - </template> - </el-dropdown> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - <!-- 淇敼涓婄骇鎺ㄥ箍浜鸿〃鍗� --> - <UpdateBindUserForm ref="updateBindUserFormRef" @success="getList" /> - <!-- 鎺ㄥ箍浜哄垪琛� --> - <BrokerageUserListDialog ref="brokerageUserListDialogRef" /> - <!-- 鎺ㄥ箍璁㈠崟鍒楄〃 --> - <BrokerageOrderListDialog ref="brokerageOrderListDialogRef" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as BrokerageUserApi from '@/api/mall/trade/brokerage/user' -import { checkPermi } from '@/utils/permission' -import { fenToYuanFormat } from '@/utils/formatter' -import UpdateBindUserForm from '@/views/mall/trade/brokerage/user/UpdateBindUserForm.vue' -import BrokerageUserListDialog from '@/views/mall/trade/brokerage/user/BrokerageUserListDialog.vue' -import BrokerageOrderListDialog from '@/views/mall/trade/brokerage/user/BrokerageOrderListDialog.vue' - -defineOptions({ name: 'TradeBrokerageUser' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - bindUserId: null, - brokerageEnabled: true, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BrokerageUserApi.getBrokerageUserPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -const handleCommand = (command: string, row: BrokerageUserApi.BrokerageUserVO) => { - switch (command) { - case 'openBrokerageUserTable': - openBrokerageUserTable(row.id) - break - case 'openBrokerageOrderTable': - openBrokerageOrderTable(row.id) - break - case 'openUpdateBindUserForm': - openUpdateBindUserForm(row) - break - case 'handleClearBindUser': - handleClearBindUser(row) - break - } -} - -/** 鎵撳紑鎺ㄥ箍浜哄垪琛� */ -const brokerageUserListDialogRef = ref() -const openBrokerageUserTable = (id: number) => { - brokerageUserListDialogRef.value.open(id) -} - -/** 鎵撳紑鎺ㄥ箍璁㈠崟鍒楄〃 */ -const brokerageOrderListDialogRef = ref() -const openBrokerageOrderTable = (id: number) => { - brokerageOrderListDialogRef.value.open(id) -} - -/** 鎵撳紑琛ㄥ崟锛氫慨鏀逛笂绾ф帹骞夸汉 */ -const updateBindUserFormRef = ref() -const openUpdateBindUserForm = (row: BrokerageUserApi.BrokerageUserVO) => { - updateBindUserFormRef.value.open(row) -} - -/** 娓呴櫎涓婄骇鎺ㄥ箍浜� */ -const handleClearBindUser = async (row: BrokerageUserApi.BrokerageUserVO) => { - try { - // 浜屾纭 - await message.confirm(`纭瑕佹竻闄�"${row.nickname}"鐨勪笂绾ф帹骞夸汉鍚楋紵`) - // 鍙戣捣淇敼 - await BrokerageUserApi.clearBindUser({ id: row.id }) - message.success('娓呴櫎鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鎺ㄥ箍璧勬牸锛氬紑閫�/鍏抽棴 */ -const handleBrokerageEnabledChange = async (row: BrokerageUserApi.BrokerageUserVO) => { - try { - // 浜屾纭 - const text = row.brokerageEnabled ? '寮�閫�' : '鍏抽棴' - await message.confirm(`纭瑕�${text}"${row.nickname}"鐨勬帹骞胯祫鏍煎悧锛焋) - // 鍙戣捣淇敼 - await BrokerageUserApi.updateBrokerageEnabled({ id: row.id, enabled: row.brokerageEnabled }) - message.success(text + '鎴愬姛') - // 鍒锋柊鍒楄〃 - await getList() - } catch { - // 寮傚父鏃讹紝闇�瑕侀噸缃洖涔嬪墠鐨勫�� - row.brokerageEnabled = !row.brokerageEnabled - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/brokerage/withdraw/BrokerageWithdrawRejectForm.vue b/src/views/mall/trade/brokerage/withdraw/BrokerageWithdrawRejectForm.vue deleted file mode 100644 index 2a69b5b..0000000 --- a/src/views/mall/trade/brokerage/withdraw/BrokerageWithdrawRejectForm.vue +++ /dev/null @@ -1,73 +0,0 @@ -<template> - <Dialog title="瀹℃牳" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="椹冲洖鍘熷洜" prop="auditReason"> - <el-input v-model="formData.auditReason" type="textarea" placeholder="璇疯緭鍏ラ┏鍥炲師鍥�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as BrokerageWithdrawApi from '@/api/mall/trade/brokerage/withdraw' - -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - auditReason: undefined -}) -const formRules = reactive({ - auditReason: [{ required: true, message: '椹冲洖鍘熷洜涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - resetForm() - formData.value.id = id -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as BrokerageWithdrawApi.BrokerageWithdrawVO - await BrokerageWithdrawApi.rejectBrokerageWithdraw(data) - message.success('椹冲洖鎴愬姛') - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - auditReason: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/trade/brokerage/withdraw/index.vue b/src/views/mall/trade/brokerage/withdraw/index.vue deleted file mode 100644 index 762451f..0000000 --- a/src/views/mall/trade/brokerage/withdraw/index.vue +++ /dev/null @@ -1,268 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝垎閿�杩斾剑" url="https://doc.iocoder.cn/mall/trade-brokerage/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-input - v-model="queryParams.userId" - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎻愮幇绫诲瀷" prop="type"> - <el-select - v-model="queryParams.type" - placeholder="璇烽�夋嫨鎻愮幇绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="璐﹀彿" prop="accountNo"> - <el-input - v-model="queryParams.accountNo" - placeholder="璇疯緭鍏ヨ处鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鎻愮幇閾惰" prop="bankName"> - <el-select - v-model="queryParams.bankName" - placeholder="璇烽�夋嫨鎻愮幇閾惰" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.BROKERAGE_BANK_NAME)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鐢宠鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="left" prop="id" min-width="60px" /> - <el-table-column label="鐢ㄦ埛淇℃伅" align="left" min-width="120px"> - <template #default="scope"> - <div>缂栧彿锛歿{ scope.row.userId }}</div> - <div>鏄电О锛歿{ scope.row.userNickname }}</div> - </template> - </el-table-column> - <el-table-column label="鎻愮幇閲戦" align="left" prop="price" min-width="80px"> - <template #default="scope"> - <div>閲戙��棰濓細锟{ fenToYuan(scope.row.price) }}</div> - <div>鎵嬬画璐癸細锟{ fenToYuan(scope.row.feePrice) }}</div> - </template> - </el-table-column> - <el-table-column label="鎻愮幇鏂瑰紡" align="left" prop="type" min-width="120px"> - <template #default="scope"> - <div v-if="scope.row.type === BrokerageWithdrawTypeEnum.WALLET.type"> 浣欓 </div> - <div v-else> - {{ getDictLabel(DICT_TYPE.BROKERAGE_WITHDRAW_TYPE, scope.row.type) }} - <span v-if="scope.row.accountNo">璐﹀彿锛歿{ scope.row.accountNo }}</span> - </div> - <template v-if="scope.row.type === BrokerageWithdrawTypeEnum.BANK.type"> - <div>鐪熷疄濮撳悕锛歿{ scope.row.name }}</div> - <div> - 閾惰鍚嶇О锛� - <dict-tag :type="DICT_TYPE.BROKERAGE_BANK_NAME" :value="scope.row.bankName" /> - </div> - <div>寮�鎴峰湴鍧�锛歿{ scope.row.bankAddress }}</div> - </template> - </template> - </el-table-column> - <el-table-column label="鏀舵鐮�" align="left" prop="accountQrCodeUrl" min-width="70px"> - <template #default="scope"> - <el-image - v-if="scope.row.accountQrCodeUrl" - :src="scope.row.accountQrCodeUrl" - class="h-40px w-40px" - :preview-src-list="[scope.row.accountQrCodeUrl]" - preview-teleported - /> - <span v-else>鏃�</span> - </template> - </el-table-column> - <el-table-column - label="鐢宠鏃堕棿" - align="left" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="澶囨敞" align="left" prop="remark" /> - <el-table-column label="鐘舵��" align="left" prop="status" min-width="120px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.BROKERAGE_WITHDRAW_STATUS" :value="scope.row.status" /> - <div v-if="scope.row.auditTime" class="text-xs"> - 鏃堕棿锛歿{ formatDate(scope.row.auditTime) }} - </div> - <div v-if="scope.row.auditReason" class="text-xs"> - 鍘熷洜锛歿{ scope.row.auditReason }} - </div> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="left" width="110px" fixed="right"> - <template #default="scope"> - <template v-if="scope.row.status === BrokerageWithdrawStatusEnum.AUDITING.status"> - <el-button - link - type="primary" - @click="handleApprove(scope.row.id)" - v-hasPermi="['trade:brokerage-withdraw:audit']" - > - 閫氳繃 - </el-button> - <el-button - link - type="danger" - @click="openForm(scope.row.id)" - v-hasPermi="['trade:brokerage-withdraw:audit']" - > - 椹冲洖 - </el-button> - </template> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <BrokerageWithdrawRejectForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getDictLabel, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import { dateFormatter, formatDate } from '@/utils/formatTime' -import * as BrokerageWithdrawApi from '@/api/mall/trade/brokerage/withdraw' -import BrokerageWithdrawRejectForm from './BrokerageWithdrawRejectForm.vue' -import { BrokerageWithdrawStatusEnum, BrokerageWithdrawTypeEnum } from '@/utils/constants' -import { fenToYuanFormat } from '@/utils/formatter' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'BrokerageWithdraw' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: null, - type: null, - name: null, - accountNo: null, - bankName: null, - status: null, - auditReason: null, - auditTime: [], - remark: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await BrokerageWithdrawApi.getBrokerageWithdrawPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (id: number) => { - formRef.value.open(id) -} - -/** 瀹℃牳閫氳繃 */ -const handleApprove = async (id: number) => { - try { - loading.value = true - await message.confirm('纭畾瑕佸鏍搁�氳繃鍚楋紵') - await BrokerageWithdrawApi.approveBrokerageWithdraw(id) - await message.success(t('common.success')) - await getList() - } finally { - loading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/config/index.vue b/src/views/mall/trade/config/index.vue deleted file mode 100644 index cdaf812..0000000 --- a/src/views/mall/trade/config/index.vue +++ /dev/null @@ -1,291 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戜氦鏄撹鍗�" url="https://doc.iocoder.cn/mall/trade-order/" /> - <doc-alert title="銆愪氦鏄撱�戣喘鐗╄溅" url="https://doc.iocoder.cn/mall/trade-cart/" /> - - <ContentWrap> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="120px" - > - <el-form-item v-show="false" label="hideId"> - <el-input v-model="formData.id" /> - </el-form-item> - <el-tabs> - <!-- 鍞悗 --> - <el-tab-pane label="鍞悗"> - <el-form-item label="閫�娆剧悊鐢�" prop="afterSaleRefundReasons"> - <el-select - v-model="formData.afterSaleRefundReasons" - allow-create - filterable - multiple - placeholder="璇风洿鎺ヨ緭鍏ラ��娆剧悊鐢�" - > - <el-option - v-for="reason in formData.afterSaleRefundReasons" - :key="reason" - :label="reason" - :value="reason" - /> - </el-select> - </el-form-item> - <el-form-item label="閫�璐х悊鐢�" prop="afterSaleReturnReasons"> - <el-select - v-model="formData.afterSaleReturnReasons" - allow-create - filterable - multiple - placeholder="璇风洿鎺ヨ緭鍏ラ��璐х悊鐢�" - > - <el-option - v-for="reason in formData.afterSaleReturnReasons" - :key="reason" - :label="reason" - :value="reason" - /> - </el-select> - </el-form-item> - </el-tab-pane> - <!-- 閰嶉�� --> - <el-tab-pane label="閰嶉��"> - <el-form-item label="鍚敤鍖呴偖" prop="deliveryExpressFreeEnabled"> - <el-switch v-model="formData.deliveryExpressFreeEnabled" style="user-select: none" /> - <el-text class="w-full" size="small" type="info"> 鍟嗗煄鏄惁鍚敤鍏ㄥ満鍖呴偖</el-text> - </el-form-item> - <el-form-item label="婊¢鍖呴偖" prop="deliveryExpressFreePrice"> - <el-input-number - v-model="formData.deliveryExpressFreePrice" - :min="0" - :precision="2" - class="!w-xs" - placeholder="璇疯緭鍏ユ弧棰濆寘閭�" - /> - <el-text class="w-full" size="small" type="info"> - 鍟嗗煄鍟嗗搧婊″灏戦噾棰濆嵆鍙寘閭紝鍗曚綅锛氬厓 - </el-text> - </el-form-item> - <el-form-item label="鍚敤闂ㄥ簵鑷彁" prop="deliveryPickUpEnabled"> - <el-switch v-model="formData.deliveryPickUpEnabled" style="user-select: none" /> - </el-form-item> - </el-tab-pane> - <!-- 鍒嗛攢 --> - <el-tab-pane label="鍒嗛攢"> - <el-form-item label="鍒嗕剑鍚敤" prop="brokerageEnabled"> - <el-switch v-model="formData.brokerageEnabled" style="user-select: none" /> - <el-text class="w-full" size="small" type="info"> 鍟嗗煄鏄惁寮�鍚垎閿�妯″紡</el-text> - </el-form-item> - <el-form-item label="鍒嗕剑妯″紡" prop="brokerageEnabledCondition"> - <el-radio-group v-model="formData.brokerageEnabledCondition"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_ENABLED_CONDITION)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - <el-text class="w-full" size="small" type="info"> - 浜轰汉鍒嗛攢锛氭瘡涓敤鎴烽兘鍙互鎴愪负鎺ㄥ箍鍛� - </el-text> - <el-text class="w-full" size="small" type="info"> - 鎸囧畾鍒嗛攢锛氫粎鍙湪鍚庡彴鎵嬪姩璁剧疆鎺ㄥ箍鍛� - </el-text> - </el-form-item> - <el-form-item label="鍒嗛攢鍏崇郴缁戝畾" prop="brokerageBindMode"> - <el-radio-group v-model="formData.brokerageBindMode"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_BIND_MODE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - <el-text class="w-full" size="small" type="info"> - 棣栨缁戝畾锛氬彧瑕佺敤鎴锋病鏈夋帹骞夸汉锛岄殢鏃堕兘鍙互缁戝畾鎺ㄥ箍鍏崇郴 - </el-text> - <el-text class="w-full" size="small" type="info"> - 娉ㄥ唽缁戝畾锛氬彧鏈夋柊鐢ㄦ埛娉ㄥ唽鏃舵垨棣栨杩涘叆绯荤粺鏃舵墠鍙互缁戝畾鎺ㄥ箍鍏崇郴 - </el-text> - </el-form-item> - <el-form-item label="鍒嗛攢娴锋姤鍥�"> - <UploadImgs v-model="formData.brokeragePosterUrls" height="125px" width="75px" /> - <el-text class="w-full" size="small" type="info"> - 涓汉涓績鍒嗛攢娴锋姤鍥剧墖锛屽缓璁昂瀵� 600x1000 - </el-text> - </el-form-item> - <el-form-item label="涓�绾ц繑浣f瘮渚�" prop="brokerageFirstPercent"> - <el-input-number - v-model="formData.brokerageFirstPercent" - :max="100" - :min="0" - class="!w-xs" - placeholder="璇疯緭鍏ヤ竴绾ц繑浣f瘮渚�" - /> - <el-text class="w-full" size="small" type="info"> - 璁㈠崟浜ゆ槗鎴愬姛鍚庣粰鎺ㄥ箍浜鸿繑浣g殑鐧惧垎姣� - </el-text> - </el-form-item> - <el-form-item label="浜岀骇杩斾剑姣斾緥" prop="brokerageSecondPercent"> - <el-input-number - v-model="formData.brokerageSecondPercent" - :max="100" - :min="0" - class="!w-xs" - placeholder="璇疯緭鍏ヤ簩绾ц繑浣f瘮渚�" - /> - <el-text class="w-full" size="small" type="info"> - 璁㈠崟浜ゆ槗鎴愬姛鍚庣粰鎺ㄥ箍浜虹殑鎺ㄨ崘浜鸿繑浣g殑鐧惧垎姣� - </el-text> - </el-form-item> - <el-form-item label="浣i噾鍐荤粨澶╂暟" prop="brokerageFrozenDays"> - <el-input-number - v-model="formData.brokerageFrozenDays" - :min="0" - class="!w-xs" - placeholder="璇疯緭鍏ヤ剑閲戝喕缁撳ぉ鏁�" - /> - <el-text class="w-full" size="small" type="info"> - 闃叉鐢ㄦ埛閫�娆撅紝浣i噾琚彁鐜颁簡锛屾墍浠ラ渶瑕佽缃剑閲戝喕缁撴椂闂达紝鍗曚綅锛氬ぉ - </el-text> - </el-form-item> - <el-form-item label="鎻愮幇鏈�浣庨噾棰�" prop="brokerageWithdrawMinPrice"> - <el-input-number - v-model="formData.brokerageWithdrawMinPrice" - :min="0" - :precision="2" - class="!w-xs" - placeholder="璇疯緭鍏ユ彁鐜版渶浣庨噾棰�" - /> - <el-text class="w-full" size="small" type="info"> - 鐢ㄦ埛鎻愮幇鏈�浣庨噾棰濋檺鍒讹紝鍗曚綅锛氬厓 - </el-text> - </el-form-item> - <el-form-item label="鎻愮幇鎵嬬画璐�" prop="brokerageWithdrawFeePercent"> - <el-input-number - v-model="formData.brokerageWithdrawFeePercent" - :max="100" - :min="0" - class="!w-xs" - placeholder="璇疯緭鍏ユ彁鐜版墜缁垂" - /> - <el-text class="w-full" size="small" type="info"> - 鎻愮幇鎵嬬画璐圭櫨鍒嗘瘮锛岃寖鍥� 0-100锛�0 涓烘棤鎻愮幇鎵嬬画璐广�備緥锛氳缃� 10锛屽嵆鏀跺彇 10% 鎵嬬画璐癸紝鎻愮幇 - 10 鍏冿紝鍒拌处 9 鍏冿紝1 鍏冩墜缁垂 - </el-text> - </el-form-item> - <el-form-item label="鎻愮幇鏂瑰紡" prop="brokerageWithdrawTypes"> - <el-checkbox-group v-model="formData.brokerageWithdrawTypes"> - <el-checkbox - v-for="dict in getIntDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_TYPE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-checkbox> - </el-checkbox-group> - <el-text class="w-full" size="small" type="info"> 鍟嗗煄寮�閫氭彁鐜扮殑浠樻鏂瑰紡</el-text> - </el-form-item> - </el-tab-pane> - </el-tabs> - <!-- 淇濆瓨 --> - <el-form-item> - <el-button :loading="formLoading" type="primary" @click="submitForm"> 淇濆瓨</el-button> - </el-form-item> - </el-form> - </ContentWrap> -</template> - -<script lang="ts" setup> -import * as ConfigApi from '@/api/mall/trade/config' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { cloneDeep } from 'lodash-es' - -defineOptions({ name: 'TradeConfig' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formRef = ref() -const formData = ref({ - id: null, - afterSaleRefundReasons: [], - afterSaleReturnReasons: [], - deliveryExpressFreeEnabled: false, - deliveryExpressFreePrice: 0, - deliveryPickUpEnabled: false, - brokerageEnabled: false, - brokerageEnabledCondition: undefined, - brokerageBindMode: undefined, - brokeragePosterUrls: [], - brokerageFirstPercent: 0, - brokerageSecondPercent: 0, - brokerageWithdrawMinPrice: 0, - brokerageWithdrawFeePercent: 0, - brokerageFrozenDays: 0, - brokerageWithdrawTypes: [] -}) -const formRules = reactive({ - deliveryExpressFreePrice: [{ required: true, message: '婊¢鍖呴偖涓嶈兘涓虹┖', trigger: 'blur' }], - brokerageEnabledCondition: [{ required: true, message: '鍒嗕剑妯″紡涓嶈兘涓虹┖', trigger: 'blur' }], - brokerageBindMode: [{ required: true, message: '鍒嗛攢鍏崇郴缁戝畾妯″紡涓嶈兘涓虹┖', trigger: 'blur' }], - brokerageFirstPercent: [{ required: true, message: '涓�绾ц繑浣f瘮渚嬩笉鑳戒负绌�', trigger: 'blur' }], - brokerageSecondPercent: [{ required: true, message: '浜岀骇杩斾剑姣斾緥涓嶈兘涓虹┖', trigger: 'blur' }], - brokerageWithdrawMinPrice: [ - { required: true, message: '鐢ㄦ埛鎻愮幇鏈�浣庨噾棰濅笉鑳戒负绌�', trigger: 'blur' } - ], - brokerageWithdrawFeePercent: [{ required: true, message: '鎻愮幇鎵嬬画璐逛笉鑳戒负绌�', trigger: 'blur' }], - brokerageFrozenDays: [{ required: true, message: '浣i噾鍐荤粨鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }], - brokerageWithdrawTypes: [ - { - required: true, - message: '鎻愮幇鏂瑰紡涓嶈兘涓虹┖', - trigger: 'change' - } - ] -}) - -const submitForm = async () => { - if (formLoading.value) return - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = cloneDeep(unref(formData.value)) as unknown as ConfigApi.ConfigVO - // 閲戦鏀惧ぇ - data.deliveryExpressFreePrice = data.deliveryExpressFreePrice * 100 - data.brokerageWithdrawMinPrice = data.brokerageWithdrawMinPrice * 100 - await ConfigApi.saveTradeConfig(data) - message.success('淇濆瓨鎴愬姛') - } finally { - formLoading.value = false - } -} - -/** 鏌ヨ浜ゆ槗涓績閰嶇疆 */ -const getConfig = async () => { - formLoading.value = true - try { - const data = await ConfigApi.getTradeConfig() - if (data != null) { - formData.value = data - // 閲戦缂╁皬 - formData.value.deliveryExpressFreePrice = data.deliveryExpressFreePrice / 100 - formData.value.brokerageWithdrawMinPrice = data.brokerageWithdrawMinPrice / 100 - } - } finally { - formLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getConfig() -}) -</script> diff --git a/src/views/mall/trade/delivery/express/ExpressForm.vue b/src/views/mall/trade/delivery/express/ExpressForm.vue deleted file mode 100644 index 232fb79..0000000 --- a/src/views/mall/trade/delivery/express/ExpressForm.vue +++ /dev/null @@ -1,126 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="鍏徃缂栫爜" prop="code"> - <el-input v-model="formData.code" placeholder="璇疯緭鍏ュ揩閫掔紪鐮�" /> - </el-form-item> - <el-form-item label="鍏徃鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ揩閫掑悕绉�" /> - </el-form-item> - <el-form-item label="鍏徃 logo" prop="logo"> - <UploadImg v-model="formData.logo" :limit="1" :is-show-tip="false" /> - <div style="font-size: 10px" class="pl-10px">鎺ㄨ崘 180x180 鍥剧墖鍒嗚鲸鐜�</div> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" controls-position="right" :min="0" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' - -defineOptions({ name: 'ExpressForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - code: '', - name: '', - logo: '', - sort: 0, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - code: [{ required: true, message: '蹇�掔紪鐮佷笉鑳戒负绌�', trigger: 'blur' }], - name: [{ required: true, message: '鍒嗙被鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - logo: [{ required: true, message: '鍒嗙被鍥剧墖涓嶈兘涓虹┖', trigger: 'blur' }], - sort: [{ required: true, message: '鍒嗙被鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await DeliveryExpressApi.getDeliveryExpress(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as DeliveryExpressApi.DeliveryExpressVO - if (formType.value === 'create') { - await DeliveryExpressApi.createDeliveryExpress(data) - message.success(t('common.createSuccess')) - } else { - await DeliveryExpressApi.updateDeliveryExpress(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - picUrl: '', - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/trade/delivery/express/index.vue b/src/views/mall/trade/delivery/express/index.vue deleted file mode 100644 index 1cde87d..0000000 --- a/src/views/mall/trade/delivery/express/index.vue +++ /dev/null @@ -1,189 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝揩閫掑彂璐�" url="https://doc.iocoder.cn/mall/trade-delivery-express/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="100px" - > - <el-form-item label="蹇�掑叕鍙哥紪鍙�" prop="code"> - <el-input - v-model="queryParams.code" - placeholder="璇疯緭蹇�掑叕鍙哥紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="蹇�掑叕鍙稿悕绉�" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭蹇�掑叕鍙稿悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['trade:delivery:express:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['trade:delivery:express:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="鍏徃缂栫爜" prop="code" /> - <el-table-column label="鍏徃鍚嶇О" prop="name" /> - <el-table-column label="鍏徃 logo " prop="logo"> - <template #default="scope"> - <img v-if="scope.row.logo" :src="scope.row.logo" alt="鍏徃logo" class="h-40px" /> - </template> - </el-table-column> - <el-table-column label="鎺掑簭" align="center" prop="sort" /> - <el-table-column label="寮�鍚姸鎬�" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['trade:delivery:express:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['trade:delivery:express:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ExpressForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' -import ExpressForm from './ExpressForm.vue' - -defineOptions({ name: 'Express' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - code: '', - name: '' -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DeliveryExpressApi.getDeliveryExpressPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DeliveryExpressApi.deleteDeliveryExpress(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await DeliveryExpressApi.exportDeliveryExpressApi(queryParams) - download.excel(data, '蹇�掑叕鍙�.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue b/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue deleted file mode 100644 index edbcbc3..0000000 --- a/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue +++ /dev/null @@ -1,321 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="1300px"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="80px" - v-loading="formLoading" - > - <el-form-item label="妯℃澘鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ユā鏉垮悕绉�" /> - </el-form-item> - <el-form-item label="璁¤垂鏂瑰紡" prop="chargeMode"> - <el-radio-group v-model="formData.chargeMode" @change="changeChargeMode"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.EXPRESS_CHARGE_MODE)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="杩愯垂" prop="charges"> - <el-table border style="width: 100%" :data="formData.charges"> - <el-table-column align="center" label="鍖哄煙" width="360"> - <template #default="{ row }"> - <el-cascader - v-model="row.areaIds" - :options="areaTree" - :props="defaultProps2" - class="w-1/1" - clearable - placeholder="璇烽�夋嫨鍦板尯" - filterable - collapse-tags - /> - </template> - </el-table-column> - <el-table-column - align="center" - :label="columnTitle.startCountTitle" - width="180" - prop="startCount" - > - <template #default="{ row }"> - <el-input-number v-model="row.startCount" :min="1" /> - </template> - </el-table-column> - <el-table-column width="180" align="center" label="杩愯垂(鍏�)" prop="startPrice"> - <template #default="{ row }"> - <el-input-number v-model="row.startPrice" :min="1" /> - </template> - </el-table-column> - <el-table-column - width="180" - align="center" - :label="columnTitle.extraCountTitle" - prop="extraCount" - > - <template #default="{ row }"> - <el-input-number v-model="row.extraCount" :min="1" /> - </template> - </el-table-column> - <el-table-column width="180" align="center" label="缁垂(鍏�)" prop="extraPrice"> - <template #default="{ row }"> - <el-input-number v-model="row.extraPrice" :min="1" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button link type="danger" @click="deleteChargeArea(scope.$index)"> - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </el-form-item> - <el-form-item> - <el-button type="primary" plain @click="addChargeArea()"> - <Icon icon="ep:plus" class="mr-5px" /> 娣诲姞鍖哄煙 - </el-button> - </el-form-item> - <el-form-item label="鍖呴偖鍖哄煙" prop="frees"> - <el-table border style="width: 100%" :data="formData.frees"> - <el-table-column align="center" label="鍖哄煙" width="360"> - <template #default="{ row }"> - <el-cascader - v-model="row.areaIds" - :options="areaTree" - :props="defaultProps2" - class="w-1/1" - clearable - placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被" - filterable - collapse-tags - /> - </template> - </el-table-column> - <el-table-column align="center" :label="columnTitle.freeCountTitle" prop="freeCount"> - <template #default="{ row }"> - <el-input-number v-model="row.freeCount" :min="1" /> - </template> - </el-table-column> - <el-table-column align="center" label="鍖呴偖閲戦锛堝厓锛�" prop="freePrice"> - <template #default="{ row }"> - <el-input-number v-model="row.freePrice" :min="1" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button link type="danger" @click="deleteFreeArea(scope.$index)"> 鍒犻櫎 </el-button> - </template> - </el-table-column> - </el-table> - </el-form-item> - <el-form-item> - <el-button type="primary" plain @click="addFreeArea()"> - <Icon icon="ep:plus" class="mr-5px" /> 娣诲姞鍖哄煙 - </el-button> - </el-form-item> - <el-form-item label="鎺掑簭" prop="sort"> - <el-input-number v-model="formData.sort" controls-position="right" :min="0" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as DeliveryExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' -import * as AreaApi from '@/api/system/area' -import { defaultProps } from '@/utils/tree' -import { yuanToFen, fenToYuan } from '@/utils' -import { cloneDeep } from 'lodash-es' -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const defaultProps2 = { - ...defaultProps, - multiple: true -} - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '', - chargeMode: 1, - sort: 0, - charges: [], - frees: [] -}) -const columnTitleMap = new Map() -const columnTitle = ref({ - startCountTitle: '棣栦欢', - extraCountTitle: '缁欢', - freeCountTitle: '鍖呴偖浠舵暟' -}) -const formRules = reactive({ - name: [{ required: true, message: '妯℃澘鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - chargeMode: [{ required: true, message: '閰嶉�佽璐规柟寮忎笉鑳戒负绌�', trigger: 'blur' }], - sort: [{ required: true, message: '鍒嗙被鎺掑簭涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - try { - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - formData.value = await DeliveryExpressTemplateApi.getDeliveryExpressTemplate(id) - columnTitle.value = columnTitleMap.get(formData.value.chargeMode) - formData.value.charges.forEach((item) => { - // 鍓嶇浠锋牸浠ュ厓灞曠ず - item.startPrice = fenToYuan(item.startPrice) - item.extraPrice = fenToYuan(item.extraPrice) - }) - formData.value.frees.forEach((item) => { - item.freePrice = fenToYuan(item.freePrice) - }) - } - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = cloneDeep(formData.value) as DeliveryExpressTemplateApi.DeliveryExpressTemplateVO - // 鍓嶇浠锋牸浠ュ厓灞曠ず锛屾彁浜ゅ埌鍚庣銆傜敤鍒嗚绠� - data.charges.forEach((item) => { - item.startPrice = yuanToFen(item.startPrice) - item.extraPrice = yuanToFen(item.extraPrice) - }) - data.frees.forEach((item) => { - item.freePrice = yuanToFen(item.freePrice) - }) - if (formType.value === 'create') { - await DeliveryExpressTemplateApi.createDeliveryExpressTemplate(data) - message.success(t('common.createSuccess')) - } else { - await DeliveryExpressTemplateApi.updateDeliveryExpressTemplate(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - chargeMode: 1, - charges: [ - { - areaIds: [1], - startCount: 2, - startPrice: 5, - extraCount: 5, - extraPrice: 10 - } - ], - frees: [], - sort: 0 - } - columnTitle.value = columnTitleMap.get(1) - formRef.value?.resetFields() -} - -/** 閰嶉�佽璐规柟娉曟敼鍙� */ -const changeChargeMode = (chargeMode: number) => { - columnTitle.value = columnTitleMap.get(chargeMode) -} - -/** 鍒濆鍖栨暟鎹� */ -const areaTree = ref([]) -const initData = async () => { - // 琛ㄥご鏍囬鍜岃璐规柟寮忕殑鏄犲皠 - columnTitleMap.set(1, { - startCountTitle: '棣栦欢', - extraCountTitle: '缁欢', - freeCountTitle: '鍖呴偖浠舵暟' - }) - columnTitleMap.set(2, { - startCountTitle: '棣栦欢閲嶉噺(kg)', - extraCountTitle: '缁欢閲嶉噺(kg)', - freeCountTitle: '鍖呴偖閲嶉噺(kg)' - }) - columnTitleMap.set(3, { - startCountTitle: '棣栦欢浣撶Н(m鲁)', - extraCountTitle: '缁欢浣撶Н(m鲁)', - freeCountTitle: '鍖呴偖浣撶Н(m鲁)' - }) - // 鍔犺浇鍖哄煙鏁版嵁 - areaTree.value = await AreaApi.getAreaTree() -} - -/** 娣诲姞璁¤垂鍖哄煙 */ -const addChargeArea = () => { - const data = formData.value - data.charges.push({ - areaIds: [], - startCount: 1, - startPrice: 1, - extraCount: 1, - extraPrice: 1 - }) -} - -/** 鍒犻櫎璁¤垂鍖哄煙 */ -const deleteChargeArea = (index) => { - const data = formData.value - data.charges.splice(index, 1) -} - -/** 娣诲姞鍖呴偖鍖哄煙 */ -const addFreeArea = () => { - const data = formData.value - data.frees.push({ - areaIds: [], - freeCount: 1, - freePrice: 1 - }) -} - -/** 鍒犻櫎鍖呴偖鍖哄煙 */ -const deleteFreeArea = (index) => { - const data = formData.value - data.frees.splice(index, 1) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - initData() -}) -</script> diff --git a/src/views/mall/trade/delivery/expressTemplate/index.vue b/src/views/mall/trade/delivery/expressTemplate/index.vue deleted file mode 100644 index 9d0688a..0000000 --- a/src/views/mall/trade/delivery/expressTemplate/index.vue +++ /dev/null @@ -1,165 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝揩閫掑彂璐�" url="https://doc.iocoder.cn/mall/trade-delivery-express/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="100px" - > - <el-form-item label="妯℃澘鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユā鏉垮悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="璁¤垂鏂瑰紡" prop="chargeMode"> - <el-select - v-model="queryParams.chargeMode" - placeholder="璁¤垂鏂瑰紡" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.EXPRESS_CHARGE_MODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['trade:delivery:express-template:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" min-width="60" prop="id" /> - <el-table-column label="妯℃澘鍚嶇О" min-width="100" prop="name" /> - <el-table-column label="璁¤垂鏂瑰紡" prop="chargeMode" min-width="100" align="center"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.EXPRESS_CHARGE_MODE" :value="scope.row.chargeMode" /> - </template> - </el-table-column> - <el-table-column label="鎺掑簭" min-width="100" prop="sort" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['trade:delivery:express-template:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['trade:delivery:express-template:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <ExpressTemplateForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as DeliveryExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' -import ExpressTemplateForm from './ExpressTemplateForm.vue' - -defineOptions({ name: 'DeliveryExpressTemplate' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: '', - chargeMode: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DeliveryExpressTemplateApi.getDeliveryExpressTemplatePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DeliveryExpressTemplateApi.deleteDeliveryExpressTemplate(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/delivery/pickUpOrder/index.vue b/src/views/mall/trade/delivery/pickUpOrder/index.vue deleted file mode 100644 index e52a3e3..0000000 --- a/src/views/mall/trade/delivery/pickUpOrder/index.vue +++ /dev/null @@ -1,328 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戜氦鏄撹鍗�" url="https://doc.iocoder.cn/mall/trade-order/" /> - <doc-alert title="銆愪氦鏄撱�戣喘鐗╄溅" url="https://doc.iocoder.cn/mall/trade-cart/" /> - - <!-- 鎼滅储 --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-280px" - end-placeholder="鑷畾涔夋椂闂�" - start-placeholder="鑷畾涔夋椂闂�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="鑷彁闂ㄥ簵" prop="pickUpStoreId"> - <el-select - v-model="queryParams.pickUpStoreId" - class="!w-280px" - clearable - multiple - placeholder="鍏ㄩ儴" - > - <el-option - v-for="item in pickUpStoreList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鑱氬悎鎼滅储"> - <el-input - v-show="true" - v-model="queryParams[queryType.queryParam]" - class="!w-280px" - clearable - placeholder="璇疯緭鍏�" - :type="queryType.queryParam === 'userId' ? 'number' : 'text'" - > - <template #prepend> - <el-select - v-model="queryType.queryParam" - class="!w-110px" - placeholder="鍏ㄩ儴" - @change="inputChangeSelect" - > - <el-option - v-for="dict in dynamicSearchList" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </template> - </el-input> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button @click="handlePickup" type="success" plain v-hasPermi="['trade:order:pick-up']"> - <Icon class="mr-5px" icon="ep:check" /> - 鏍搁攢 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 缁熻鍗$墖 --> - <el-row :gutter="16" class="summary"> - <el-col :sm="6" :xs="12" v-loading="loading"> - <SummaryCard - title="璁㈠崟鏁伴噺" - icon="icon-park-outline:transaction-order" - icon-color="bg-blue-100" - icon-bg-color="text-blue-500" - :value="summary?.orderCount || 0" - /> - </el-col> - <el-col :sm="6" :xs="12" v-loading="loading"> - <SummaryCard - title="璁㈠崟閲戦" - icon="streamline:money-cash-file-dollar-common-money-currency-cash-file" - icon-color="bg-purple-100" - icon-bg-color="text-purple-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(summary?.orderPayPrice || 0)" - /> - </el-col> - <el-col :sm="6" :xs="12" v-loading="loading"> - <SummaryCard - title="閫�娆惧崟鏁�" - icon="heroicons:receipt-refund" - icon-color="bg-yellow-100" - icon-bg-color="text-yellow-500" - :value="summary?.afterSaleCount || 0" - /> - </el-col> - <el-col :sm="6" :xs="12" v-loading="loading"> - <SummaryCard - title="閫�娆鹃噾棰�" - icon="ri:refund-2-line" - icon-color="bg-green-100" - icon-bg-color="text-green-500" - prefix="锟�" - :decimals="2" - :value="fenToYuan(summary?.afterSalePrice || 0)" - /> - </el-col> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="璁㈠崟鍙�" align="center" prop="no" min-width="180" /> - <el-table-column label="鐢ㄦ埛淇℃伅" align="center" prop="user.nickname" min-width="80" /> - <el-table-column - label="鎺ㄨ崘浜轰俊鎭�" - align="center" - prop="brokerageUser.nickname" - min-width="100" - /> - <el-table-column label="鍟嗗搧淇℃伅" align="center" prop="spuName" min-width="300"> - <template #default="{ row }"> - <div class="flex items-center" v-for="item in row.items" :key="item.id"> - <el-image - :src="item.picUrl" - class="mr-10px h-30px w-30px flex-shrink-0" - :preview-src-list="[item.picUrl]" - preview-teleported - /> - <span class="mr-10px">{{ item.spuName }}</span> - <div class="flex flex-col flex-wrap gap-1"> - <el-tag - v-for="property in item.properties" - :key="property.propertyId" - class="mr-10px" - > - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - <span>{{ floatToFixed2(item.price) }} 鍏� x {{ item.count }}</span> - </div> - </div> - </template> - </el-table-column> - <el-table-column - label="瀹炰粯閲戦(鍏�)" - align="center" - prop="payPrice" - min-width="110" - :formatter="fenToYuanFormat" - /> - <el-table-column label="鏍搁攢鍛�" align="center" prop="storeStaffName" min-width="70" /> - <el-table-column label="鏍搁攢闂ㄥ簵" align="center" prop="pickUpStoreId" min-width="80"> - <template #default="{ row }"> - {{ pickUpStoreList.find((p) => p.id === row.pickUpStoreId)?.name }} - </template> - </el-table-column> - <el-table-column label="鏀粯鐘舵��" align="center" prop="payStatus" min-width="80"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.payStatus || false" /> - </template> - </el-table-column> - <el-table-column align="center" label="璁㈠崟鐘舵��" prop="status" width="120"> - <template #default="{ row }"> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="row.status" /> - </template> - </el-table-column> - <el-table-column - label="涓嬪崟鏃堕棿" - align="center" - prop="createTime" - min-width="170" - :formatter="dateFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 鍚勭鎿嶄綔鐨勫脊绐� --> - <OrderPickUpForm ref="pickUpForm" @success="getList" /> -</template> - -<script lang="ts" setup> -import type { FormInstance } from 'element-plus' -import * as TradeOrderApi from '@/api/mall/trade/order' -import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import { DICT_TYPE } from '@/utils/dict' -import { fenToYuan, floatToFixed2 } from '@/utils' -import { fenToYuanFormat } from '@/utils/formatter' -import SummaryCard from '@/components/SummaryCard/index.vue' -import { dateFormatter } from '@/utils/formatTime' -import { DeliveryTypeEnum } from '@/utils/constants' -import { TradeOrderSummaryRespVO } from '@/api/mall/trade/order' -import { DeliveryPickUpStoreVO } from '@/api/mall/trade/delivery/pickUpStore' -import OrderPickUpForm from '@/views/mall/trade/order/form/OrderPickUpForm.vue' - -defineOptions({ name: 'PickUpOrder' }) - -// 鍒楄〃鐨勫姞杞戒腑 -const loading = ref(true) -// 鍒楄〃鐨勬�婚〉鏁� -const total = ref(2) -// 鍒楄〃鐨勬暟鎹� -const list = ref<TradeOrderApi.OrderVO[]>([]) -// 鎼滅储鐨勮〃鍗� -const queryFormRef = ref<FormInstance>() -// 鍒濆琛ㄥ崟鍙傛暟 -const INIT_QUERY_PARAMS = { - // 椤垫暟 - pageNo: 1, - // 姣忛〉鏄剧ず鏁伴噺 - pageSize: 10, - // 鍒涘缓鏃堕棿 - createTime: undefined, - // 閰嶉�佹柟寮� - deliveryType: DeliveryTypeEnum.PICK_UP.type, - // 鑷彁闂ㄥ簵 - pickUpStoreId: undefined -} -// 琛ㄥ崟鎼滅储 -const queryParams = ref({ ...INIT_QUERY_PARAMS }) -// 璁㈠崟鎼滅储绫诲瀷 queryParam -const queryType = reactive({ queryParam: 'no' }) -// 璁㈠崟缁熻鏁版嵁 -const summary = ref<TradeOrderSummaryRespVO>() - -// 璁㈠崟鑱氬悎鎼滅储 select 绫诲瀷閰嶇疆锛堝姩鎬佹悳绱級 -const dynamicSearchList = ref([ - { value: 'no', label: '璁㈠崟鍙�' }, - { value: 'userId', label: '鐢ㄦ埛UID' }, - { value: 'userNickname', label: '鐢ㄦ埛鏄电О' }, - { value: 'userMobile', label: '鐢ㄦ埛鐢佃瘽' } -]) -/** - * 鑱氬悎鎼滅储鍒囨崲鏌ヨ瀵硅薄鏃惰Е鍙� - * @param val - */ -const inputChangeSelect = (val: string) => { - dynamicSearchList.value - .filter((item) => item.value !== val) - ?.forEach((item) => { - // 娓呴櫎闆嗗悎鎼滅储鏃犵敤灞炴�� - if (queryParams.value.hasOwnProperty(item.value)) { - delete queryParams.value[item.value] - } - }) -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - // 缁熻 - summary.value = await TradeOrderApi.getOrderSummary(unref(queryParams)) - // 鍒嗛〉 - const data = await TradeOrderApi.getOrderPage(unref(queryParams)) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = async () => { - queryParams.value.pageNo = 1 - await getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - queryParams.value = { ...INIT_QUERY_PARAMS } - handleQuery() -} - -/** 鑷彁闂ㄥ簵绮剧畝鍒楄〃 */ -const pickUpStoreList = ref<DeliveryPickUpStoreVO[]>([]) -const getPickUpStoreList = async () => { - pickUpStoreList.value = await PickUpStoreApi.getListAllSimple() -} - -/** 鏄剧ず鏍搁攢琛ㄥ崟 */ -const pickUpForm = ref() -const handlePickup = () => { - pickUpForm.value.open() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() - getPickUpStoreList() -}) -</script> -<style lang="scss" scoped> -:deep(.order-table-col > .cell) { - padding: 0; -} - -.summary { - .el-col { - margin-bottom: 1rem; - } -} -</style> diff --git a/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue b/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue deleted file mode 100644 index 5900558..0000000 --- a/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue +++ /dev/null @@ -1,273 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="60%"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-row> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵 logo" prop="logo"> - <UploadImg v-model="formData.logo" :limit="1" :is-show-tip="false" /> - <div style="font-size: 10px" class="pl-10px">鎺ㄨ崘 180x180 鍥剧墖鍒嗚鲸鐜�</div> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ラ棬搴楀悕绉�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵鎵嬫満" prop="phone"> - <el-input v-model="formData.phone" placeholder="璇疯緭鍏ラ棬搴楁墜鏈�" /> - </el-form-item> - </el-col> - </el-row> - <el-form-item label="闂ㄥ簵绠�浠�" prop="introduction"> - <el-input - v-model="formData.introduction" - :rows="3" - type="textarea" - placeholder="璇疯緭鍏ラ棬搴楃畝浠�" - /> - </el-form-item> - <el-row> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵鎵�鍦ㄥ湴鍖�" prop="areaId"> - <el-cascader v-model="formData.areaId" :options="areaList" :props="defaultProps" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="闂ㄥ簵璇︾粏鍦板潃" prop="detailAddress"> - <el-input v-model="formData.detailAddress" placeholder="璇疯緭鍏ラ棬搴楄缁嗗湴鍧�" /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="钀ヤ笟寮�濮嬫椂闂�" prop="openingTime"> - <el-time-select - v-model="formData.openingTime" - :max-time="formData.closingTime" - placeholder="寮�濮嬫椂闂�" - start="08:30" - step="00:15" - end="23:30" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="钀ヤ笟缁撴潫鏃堕棿" prop="closingTime"> - <el-time-select - v-model="formData.closingTime" - :min-time="formData.openingTime" - placeholder="缁撴潫鏃堕棿" - start="08:30" - step="00:15" - end="23:30" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="缁忓害" prop="longitude"> - <el-input v-model="formData.longitude" placeholder="璇疯緭鍏ラ棬搴楃粡搴�" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绾害" prop="latitude"> - <el-input v-model="formData.latitude" placeholder="璇疯緭鍏ラ棬搴楃含搴�" /> - </el-form-item> - </el-col> - </el-row> - <el-form-item label="鑾峰彇缁忕含搴�"> - <el-button type="primary" @click="mapDialogVisible = true">鑾峰彇</el-button> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - <el-dialog - v-model="mapDialogVisible" - title="鑾峰彇缁忕含搴�" - append-to-body - width="500px" - class="mapBox" - > - <iframe id="mapPage" width="100%" height="100%" frameborder="0" :src="tencentLbsUrl"></iframe> - </el-dialog> - </Dialog> -</template> -<script setup lang="ts"> -import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { CommonStatusEnum } from '@/utils/constants' -import { defaultProps } from '@/utils/tree' -import { getAreaTree } from '@/api/system/area' -import * as ConfigApi from '@/api/mall/trade/config' -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const mapDialogVisible = ref(false) // 鍦板浘寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: '', - phone: '', - logo: '', - detailAddress: '', - introduction: '', - areaId: 0, - openingTime: undefined, - closingTime: undefined, - latitude: undefined, - longitude: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '闂ㄥ簵鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - logo: [{ required: true, message: '闂ㄥ簵 logo 涓嶈兘涓虹┖', trigger: 'blur' }], - phone: [ - { required: true, message: '闂ㄥ簵鎵嬫満涓嶈兘涓虹┖', trigger: 'blur' }, - { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '璇疯緭鍏ユ纭殑鎵嬫満鍙风爜', trigger: 'blur' } - ], - areaId: [{ required: true, message: '闂ㄥ簵鎵�鍦ㄥ尯鍩熶笉鑳戒负绌�', trigger: 'blur' }], - detailAddress: [{ required: true, message: '闂ㄥ簵璇︾粏鍦板潃涓嶈兘涓虹┖', trigger: 'blur' }], - openingTime: [{ required: true, message: '钀ヤ笟寮�濮嬫椂闂翠笉鑳戒负绌�', trigger: 'blur' }], - closingTime: [{ required: true, message: '钀ヤ笟缁撴潫鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }], - latitude: [{ required: true, message: '绾害涓嶈兘涓虹┖', trigger: 'blur' }], - longitude: [{ required: true, message: '缁忓害涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const areaList = ref() // 鍖哄煙鏍� -const tencentLbsUrl = ref('') // 鑵捐浣嶇疆鏈嶅姟 url - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await DeliveryPickUpStoreApi.getDeliveryPickUpStore(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as DeliveryPickUpStoreApi.DeliveryPickUpStoreVO - if (formType.value === 'create') { - await DeliveryPickUpStoreApi.createDeliveryPickUpStore(data) - message.success(t('common.createSuccess')) - } else { - await DeliveryPickUpStoreApi.updateDeliveryPickUpStore(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - phone: '', - logo: '', - detailAddress: '', - introduction: '', - areaId: undefined, - openingTime: undefined, - closingTime: undefined, - latitude: undefined, - longitude: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} - -/** 閫夋嫨缁忕含搴� */ -const selectAddress = function (loc: any): void { - if (loc.latlng && loc.latlng.lat) { - formData.value.latitude = loc.latlng.lat - } - if (loc.latlng && loc.latlng.lng) { - formData.value.longitude = loc.latlng.lng - } - mapDialogVisible.value = false -} - -/** 鍒濆鍖栬吘璁湴鍥� */ -const initTencentLbsMap = async () => { - window.selectAddress = selectAddress - window.addEventListener( - 'message', - function (event) { - // 鎺ユ敹浣嶇疆淇℃伅锛岀敤鎴烽�夋嫨纭浣嶇疆鐐瑰悗閫夌偣缁勪欢浼氳Е鍙戣浜嬩欢锛屽洖浼犵敤鎴风殑浣嶇疆淇℃伅 - let loc = event.data - if (loc && loc.module === 'locationPicker') { - // 闃叉鍏朵粬搴旂敤涔熶細鍚戣椤甸潰 post 淇℃伅锛岄渶鍒ゆ柇 module 鏄惁涓� 'locationPicker' - window.parent.selectAddress(loc) - } - }, - false - ) - const data = await ConfigApi.getTradeConfig() - const key = data.tencentLbsKey - tencentLbsUrl.value = `https://apis.map.qq.com/tools/locpicker?type=1&key=${key}&referer=myapp` -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - areaList.value = await getAreaTree() - // 鍔犺浇鍦板浘 - await initTencentLbsMap() -}) -</script> -<style lang="scss"> -.mapBox .el-dialog__body { - height: 640px !important; -} -</style> diff --git a/src/views/mall/trade/delivery/pickUpStore/index.vue b/src/views/mall/trade/delivery/pickUpStore/index.vue deleted file mode 100644 index eddf64e..0000000 --- a/src/views/mall/trade/delivery/pickUpStore/index.vue +++ /dev/null @@ -1,190 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戝揩閫掑彂璐�" url="https://doc.iocoder.cn/mall/trade-delivery-express/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px"> - <el-form-item label="闂ㄥ簵鎵嬫満" prop="phone"> - <el-input - v-model="queryParams.phone" - class="!w-240px" - clearable - placeholder="璇疯緭闂ㄥ簵鎵嬫満" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="闂ㄥ簵鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="璇疯緭闂ㄥ簵鍚嶇О" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="闂ㄥ簵鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="闂ㄥ簵鐘舵��"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="datetimerange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button - v-hasPermi="['trade:delivery:pick-up-store:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" min-width="80" prop="id" /> - <el-table-column label="闂ㄥ簵 logo" min-width="100" prop="logo"> - <template #default="scope"> - <img v-if="scope.row.logo" :src="scope.row.logo" alt="闂ㄥ簵 logo" class="h-50px" /> - </template> - </el-table-column> - <el-table-column label="闂ㄥ簵鍚嶇О" min-width="150" prop="name" /> - <el-table-column label="闂ㄥ簵鎵嬫満" min-width="100" prop="phone" /> - <el-table-column label="鍦板潃" min-width="100" prop="detailAddress" /> - <el-table-column label="钀ヤ笟鏃堕棿" min-width="180"> - <template #default="scope"> - {{ scope.row.openingTime }} ~ {{ scope.row.closingTime }} - </template> - </el-table-column> - <el-table-column align="center" label="寮�鍚姸鎬�" min-width="100" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鍒涘缓鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="鎿嶄綔"> - <template #default="scope"> - <el-button - v-hasPermi="['trade:delivery:pick-up-store:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 缂栬緫 - </el-button> - <el-button - v-hasPermi="['trade:delivery:pick-up-store:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <DeliveryPickUpStoreForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" name="DeliveryPickUpStore" setup> -import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import DeliveryPickUpStoreForm from './PickUpStoreForm.vue' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref<any[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - status: undefined, - phone: undefined, - name: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await DeliveryPickUpStoreApi.deleteDeliveryPickUpStore(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DeliveryPickUpStoreApi.getDeliveryPickUpStorePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/mall/trade/order/components/OrderTableColumn.vue b/src/views/mall/trade/order/components/OrderTableColumn.vue deleted file mode 100644 index 5d1e25e..0000000 --- a/src/views/mall/trade/order/components/OrderTableColumn.vue +++ /dev/null @@ -1,263 +0,0 @@ -<template> - <el-table-column class-name="order-table-col"> - <template #header> - <div class="flex items-center" style="width: 100%"> - <div :style="{ width: orderTableHeadWidthList[0] + 'px' }" class="flex justify-center"> - 鍟嗗搧淇℃伅 - </div> - <div :style="{ width: orderTableHeadWidthList[1] + 'px' }" class="flex justify-center"> - 鍗曚环(鍏�)/鏁伴噺 - </div> - <div :style="{ width: orderTableHeadWidthList[2] + 'px' }" class="flex justify-center"> - 鍞悗鐘舵�� - </div> - <div :style="{ width: orderTableHeadWidthList[3] + 'px' }" class="flex justify-center"> - 瀹炰粯閲戦(鍏�) - </div> - <div :style="{ width: orderTableHeadWidthList[4] + 'px' }" class="flex justify-center"> - 涔板/鏀惰揣浜� - </div> - <div :style="{ width: orderTableHeadWidthList[5] + 'px' }" class="flex justify-center"> - 閰嶉�佹柟寮� - </div> - <div :style="{ width: orderTableHeadWidthList[6] + 'px' }" class="flex justify-center"> - 璁㈠崟鐘舵�� - </div> - <div :style="{ width: orderTableHeadWidthList[7] + 'px' }" class="flex justify-center"> - 鎿嶄綔 - </div> - </div> - </template> - <template #default="scope"> - <el-table - :ref="setOrderTableRef" - :border="true" - :data="scope.row.items" - :header-cell-style="headerStyle" - :span-method="spanMethod" - style="width: 100%" - > - <el-table-column min-width="300" prop="spuName"> - <template #header> - <div - class="mr-[20px] h-[35px] flex items-center pl-[10px] pr-[10px]" - style="background-color: #f7f7f7" - > - <span class="mr-20px">璁㈠崟鍙凤細{{ scope.row.no }} </span> - <span class="mr-20px">涓嬪崟鏃堕棿锛歿{ formatDate(scope.row.createTime) }}</span> - <span>璁㈠崟鏉ユ簮锛�</span> - <dict-tag :type="DICT_TYPE.TERMINAL" :value="scope.row.terminal" class="mr-20px" /> - <span>鏀粯鏂瑰紡锛�</span> - <dict-tag - v-if="scope.row.payChannelCode" - :type="DICT_TYPE.PAY_CHANNEL_CODE" - :value="scope.row.payChannelCode" - class="mr-20px" - /> - <span v-else class="mr-20px">鏈敮浠�</span> - <span v-if="scope.row.payTime" class="mr-20px"> - 鏀粯鏃堕棿锛歿{ formatDate(scope.row.payTime) }} - </span> - <span>璁㈠崟绫诲瀷锛�</span> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="scope.row.type" /> - </div> - </template> - <template #default="{ row }"> - <div class="flex flex-wrap"> - <div class="mb-[10px] mr-[10px] flex items-start"> - <div class="mr-[10px]"> - <el-image - :src="row.picUrl" - class="!h-[45px] !w-[45px]" - fit="contain" - @click="imagePreview(row.picUrl)" - > - <template #error> - <div class="image-slot"> - <icon icon="ep:picture" /> - </div> - </template> - </el-image> - </div> - <ElTooltip :content="row.spuName" placement="top"> - <span class="overflow-ellipsis max-h-[45px] overflow-hidden"> - {{ row.spuName }} - </span> - </ElTooltip> - </div> - <el-tag - v-for="property in row.properties" - :key="property.propertyId" - class="mb-[10px] mr-[10px]" - > - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </div> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍘熶环*鏁伴噺" prop="price" width="150"> - <template #default="{ row }"> - {{ floatToFixed2(row.price) }} 鍏� / {{ row.count }} - </template> - </el-table-column> - <el-table-column label="鍞悗鐘舵��" prop="afterSaleStatus" width="120"> - <template #default="{ row }"> - <dict-tag - :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS" - :value="row.afterSaleStatus" - /> - </template> - </el-table-column> - <el-table-column align="center" label="瀹為檯鏀粯" min-width="120" prop="payPrice"> - <template #default> - {{ floatToFixed2(scope.row.payPrice) + '鍏�' }} - </template> - </el-table-column> - <el-table-column label="涔板/鏀惰揣浜�" min-width="160"> - <template #default> - <!-- 蹇�掑彂璐� --> - <div - v-if="scope.row.deliveryType === DeliveryTypeEnum.EXPRESS.type" - class="flex flex-col" - > - <span>涔板锛歿{ scope.row.user.nickname }}</span> - <span> - 鏀惰揣浜猴細{{ scope.row.receiverName }} {{ scope.row.receiverMobile }} - {{ scope.row.receiverAreaName }} {{ scope.row.receiverDetailAddress }} - </span> - </div> - <!-- 鑷彁 --> - <div - v-if="scope.row.deliveryType === DeliveryTypeEnum.PICK_UP.type" - class="flex flex-col" - > - <span> - 闂ㄥ簵鍚嶇О锛� - {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.name }} - </span> - <span> - 闂ㄥ簵鎵嬫満锛� - {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.phone }} - </span> - <span> - 鑷彁闂ㄥ簵: - {{ pickUpStoreList.find((p) => p.id === scope.row.pickUpStoreId)?.detailAddress }} - </span> - </div> - </template> - </el-table-column> - <el-table-column align="center" label="閰嶉�佹柟寮�" width="120"> - <template #default> - <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="scope.row.deliveryType" /> - </template> - </el-table-column> - <el-table-column align="center" label="璁㈠崟鐘舵��" width="120"> - <template #default> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="鎿嶄綔" width="160"> - <template #default> - <slot :row="scope.row"></slot> - </template> - </el-table-column> - </el-table> - </template> - </el-table-column> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { DeliveryTypeEnum } from '@/utils/constants' -import { formatDate } from '@/utils/formatTime' -import { floatToFixed2 } from '@/utils' -import * as TradeOrderApi from '@/api/mall/trade/order' -import { OrderVO } from '@/api/mall/trade/order' -import type { TableColumnCtx, TableInstance } from 'element-plus' -import { createImageViewer } from '@/components/ImageViewer' -import type { DeliveryPickUpStoreVO } from '@/api/mall/trade/delivery/pickUpStore' - -defineOptions({ name: 'OrderTableColumn' }) - -const props = defineProps<{ - list: OrderVO[] - pickUpStoreList: DeliveryPickUpStoreVO[] -}>() - -const headerStyle = ({ row, columnIndex }: any) => { - // 琛ㄥご绗竴琛岀涓�鍒楀崰 8 - if (columnIndex === 0) { - row[columnIndex].colSpan = 8 - } else { - // 鍏朵綑鐨勪笉瑕� - row[columnIndex].colSpan = 0 - return { - display: 'none' - } - } -} - -interface SpanMethodProps { - row: TradeOrderApi.OrderItemRespVO - column: TableColumnCtx<TradeOrderApi.OrderItemRespVO> - rowIndex: number - columnIndex: number -} - -type spanMethodResp = number[] | { rowspan: number; colspan: number } | undefined -const spanMethod = ({ row, rowIndex, columnIndex }: SpanMethodProps): spanMethodResp => { - const len = props.list.find( - (order) => order.items?.findIndex((item) => item.id === row.id) !== -1 - )?.items?.length - // 瑕佸悎骞剁殑鍒楋紝浠庨浂寮�濮� - const colIndex = [3, 4, 5, 6, 7] - if (colIndex.includes(columnIndex)) { - // 闄や簡绗竴琛屽叾浣欑殑涓嶈 - if (rowIndex !== 0) { - return { - rowspan: 0, - colspan: 0 - } - } - // 鍔ㄦ�佸悎骞惰 - return { - rowspan: len!, - colspan: 1 - } - } -} - -/** 瑙e喅 ref 鍦� v-for 涓殑鑾峰彇闂*/ -const setOrderTableRef = (el: TableInstance) => { - if (!el) return - // 鍙绗竴涓〃涔熷氨鏄紑濮嬬殑绗竴琛� - if (el.tableId !== 'el-table_2') { - return - } - tableHeadWidthAuto(el) -} -// 澶撮儴 col 瀹藉害鍒濆鍖� -const orderTableHeadWidthList = ref([300, 150, 120, 120, 160, 120, 120, 160]) -// 澶撮儴瀹藉害鑷�傚簲 -const tableHeadWidthAuto = (el: TableInstance) => { - const columns = el.store.states.columns.value - if (columns.length === 0) { - return - } - columns.forEach((col: TableColumnCtx<TableInstance>, index: number) => { - if (col.realWidth) { - orderTableHeadWidthList.value[index] = col.realWidth - } - }) -} -/** 鍟嗗搧鍥鹃瑙� */ -const imagePreview = (imgUrl: string) => { - createImageViewer({ - urlList: [imgUrl] - }) -} -</script> -<style lang="scss" scoped> -:deep(.order-table-col > .cell) { - padding: 0; -} -</style> diff --git a/src/views/mall/trade/order/components/index.ts b/src/views/mall/trade/order/components/index.ts deleted file mode 100644 index 9cce9fa..0000000 --- a/src/views/mall/trade/order/components/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import OrderTableColumn from './OrderTableColumn.vue' - -export { OrderTableColumn } diff --git a/src/views/mall/trade/order/detail/index.vue b/src/views/mall/trade/order/detail/index.vue deleted file mode 100644 index 67e5476..0000000 --- a/src/views/mall/trade/order/detail/index.vue +++ /dev/null @@ -1,426 +0,0 @@ -<template> - <ContentWrap> - <!-- 璁㈠崟淇℃伅 --> - <el-descriptions title="璁㈠崟淇℃伅"> - <el-descriptions-item label="璁㈠崟鍙�: ">{{ formData.no }}</el-descriptions-item> - <el-descriptions-item label="涔板: ">{{ formData?.user?.nickname }}</el-descriptions-item> - <el-descriptions-item label="璁㈠崟绫诲瀷: "> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="formData.type!" /> - </el-descriptions-item> - <el-descriptions-item label="璁㈠崟鏉ユ簮: "> - <dict-tag :type="DICT_TYPE.TERMINAL" :value="formData.terminal!" /> - </el-descriptions-item> - <el-descriptions-item label="涔板鐣欒█: ">{{ formData.userRemark }}</el-descriptions-item> - <el-descriptions-item label="鍟嗗澶囨敞: ">{{ formData.remark }}</el-descriptions-item> - <el-descriptions-item label="鏀粯鍗曞彿: ">{{ formData.payOrderId }}</el-descriptions-item> - <el-descriptions-item label="浠樻鏂瑰紡: "> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="formData.payChannelCode!" /> - </el-descriptions-item> - <el-descriptions-item v-if="formData.brokerageUser" label="鎺ㄥ箍鐢ㄦ埛: "> - {{ formData.brokerageUser?.nickname }} - </el-descriptions-item> - </el-descriptions> - - <!-- 璁㈠崟鐘舵�� --> - <el-descriptions :column="1" title="璁㈠崟鐘舵��"> - <el-descriptions-item label="璁㈠崟鐘舵��: "> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="formData.status!" /> - </el-descriptions-item> - <el-descriptions-item v-hasPermi="['trade:order:update']" label-class-name="no-colon"> - <el-button - v-if="formData.status! === TradeOrderStatusEnum.UNPAID.status" - type="primary" - @click="updatePrice" - > - 璋冩暣浠锋牸 - </el-button> - <el-button type="primary" @click="remark">澶囨敞</el-button> - <!-- 寰呭彂璐� --> - <template v-if="formData.status! === TradeOrderStatusEnum.UNDELIVERED.status"> - <!-- 蹇�掑彂璐� --> - <el-button - v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" - type="primary" - @click="delivery" - > - 鍙戣揣 - </el-button> - <el-button - v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" - type="primary" - @click="updateAddress" - > - 淇敼鍦板潃 - </el-button> - <!-- 鍒板簵鑷彁 --> - <el-button - v-if="formData.deliveryType === DeliveryTypeEnum.PICK_UP.type && showPickUp" - type="primary" - @click="handlePickUp" - > - 鏍搁攢 - </el-button> - </template> - </el-descriptions-item> - <el-descriptions-item> - <template #label><span style="color: red">鎻愰啋: </span></template> - 涔板浠樻鎴愬姛鍚庯紝璐ф灏嗙洿鎺ヨ繘鍏ユ偍鐨勫晢鎴峰彿锛堝井淇°�佹敮浠樺疂锛�<br /> - 璇峰強鏃跺叧娉ㄤ綘鍙戝嚭鐨勫寘瑁圭姸鎬侊紝纭繚鍙互閰嶉�佽嚦涔板鎵嬩腑 <br /> - 濡傛灉涔板琛ㄧず娌℃敹鍒拌揣鎴栬揣鐗╂湁闂锛岃鍙婃椂鑱旂郴涔板澶勭悊锛屽弸濂藉崗鍟� - </el-descriptions-item> - </el-descriptions> - - <!-- 鍟嗗搧淇℃伅 --> - <el-descriptions title="鍟嗗搧淇℃伅"> - <el-descriptions-item labelClassName="no-colon"> - <el-row :gutter="20"> - <el-col :span="15"> - <el-table :data="formData.items" border> - <el-table-column label="鍟嗗搧" prop="spuName" width="auto"> - <template #default="{ row }"> - {{ row.spuName }} - <el-tag v-for="property in row.properties" :key="property.propertyId"> - {{ property.propertyName }}: {{ property.valueName }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鍟嗗搧鍘熶环" prop="price" width="150"> - <template #default="{ row }">{{ fenToYuan(row.price) }}鍏�</template> - </el-table-column> - <el-table-column label="鏁伴噺" prop="count" width="100" /> - <el-table-column label="鍚堣" prop="payPrice" width="150"> - <template #default="{ row }">{{ fenToYuan(row.payPrice) }}鍏�</template> - </el-table-column> - <el-table-column label="鍞悗鐘舵��" prop="afterSaleStatus" width="120"> - <template #default="{ row }"> - <dict-tag - :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS" - :value="row.afterSaleStatus" - /> - </template> - </el-table-column> - </el-table> - </el-col> - <el-col :span="10" /> - </el-row> - </el-descriptions-item> - </el-descriptions> - <el-descriptions :column="4"> - <!-- 绗竴灞� --> - <el-descriptions-item label="鍟嗗搧鎬婚: "> - {{ fenToYuan(formData.totalPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item label="杩愯垂閲戦: "> - {{ fenToYuan(formData.deliveryPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item label="璁㈠崟璋冧环: "> - {{ fenToYuan(formData.adjustPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item v-for="item in 1" :key="item" label-class-name="no-colon" /> - <!-- 绗簩灞� --> - <el-descriptions-item> - <template #label><span style="color: red">浼樻儬鍔典紭鎯�: </span></template> - {{ fenToYuan(formData.couponPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item> - <template #label><span style="color: red">VIP 浼樻儬: </span></template> - {{ fenToYuan(formData.vipPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item> - <template #label><span style="color: red">娲诲姩浼樻儬: </span></template> - {{ fenToYuan(formData.discountPrice!) }} 鍏� - </el-descriptions-item> - <el-descriptions-item> - <template #label><span style="color: red">绉垎鎶垫墸: </span></template> - {{ fenToYuan(formData.pointPrice!) }} 鍏� - </el-descriptions-item> - <!-- 绗笁灞� --> - <el-descriptions-item v-for="item in 3" :key="item" label-class-name="no-colon" /> - <el-descriptions-item label="搴斾粯閲戦: "> - {{ fenToYuan(formData.payPrice!) }} 鍏� - </el-descriptions-item> - </el-descriptions> - - <!-- 鐗╂祦淇℃伅 --> - <el-descriptions :column="4" title="鏀惰揣淇℃伅"> - <el-descriptions-item label="閰嶉�佹柟寮�: "> - <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="formData.deliveryType!" /> - </el-descriptions-item> - <el-descriptions-item label="鏀惰揣浜�: ">{{ formData.receiverName }}</el-descriptions-item> - <el-descriptions-item label="鑱旂郴鐢佃瘽: ">{{ formData.receiverMobile }}</el-descriptions-item> - <!-- 蹇�掗厤閫� --> - <div v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type"> - <el-descriptions-item v-if="formData.receiverDetailAddress" label="鏀惰揣鍦板潃: "> - {{ formData.receiverAreaName }} {{ formData.receiverDetailAddress }} - <el-link - v-clipboard:copy="formData.receiverAreaName + ' ' + formData.receiverDetailAddress" - v-clipboard:success="clipboardSuccess" - icon="ep:document-copy" - type="primary" - /> - </el-descriptions-item> - <el-descriptions-item v-if="formData.logisticsId" label="鐗╂祦鍏徃: "> - {{ deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name }} - </el-descriptions-item> - <el-descriptions-item v-if="formData.logisticsId" label="杩愬崟鍙�: "> - {{ formData.logisticsNo }} - </el-descriptions-item> - <el-descriptions-item v-if="formatDate.deliveryTime" label="鍙戣揣鏃堕棿: "> - {{ formatDate(formData.deliveryTime) }} - </el-descriptions-item> - <el-descriptions-item v-for="item in 2" :key="item" label-class-name="no-colon" /> - <el-descriptions-item v-if="expressTrackList.length > 0" label="鐗╂祦璇︽儏: "> - <el-timeline> - <el-timeline-item - v-for="(express, index) in expressTrackList" - :key="index" - :timestamp="formatDate(express.time)" - > - {{ express.content }} - </el-timeline-item> - </el-timeline> - </el-descriptions-item> - </div> - <!-- 鑷彁闂ㄥ簵 --> - <div v-if="formData.deliveryType === DeliveryTypeEnum.PICK_UP.type"> - <el-descriptions-item v-if="formData.pickUpStoreId" label="鑷彁闂ㄥ簵: "> - {{ pickUpStore?.name }} - </el-descriptions-item> - </div> - </el-descriptions> - - <!-- 璁㈠崟鏃ュ織 --> - <el-descriptions title="璁㈠崟鎿嶄綔鏃ュ織"> - <el-descriptions-item labelClassName="no-colon"> - <el-timeline> - <el-timeline-item - v-for="(log, index) in formData.logs" - :key="index" - :timestamp="formatDate(log.createTime!)" - placement="top" - > - <div class="el-timeline-right-content"> - {{ log.content }} - </div> - <template #dot> - <span - :style="{ backgroundColor: getUserTypeColor(log.userType!) }" - class="dot-node-style" - > - {{ getDictLabel(DICT_TYPE.USER_TYPE, log.userType)[0] }} - </span> - </template> - </el-timeline-item> - </el-timeline> - </el-descriptions-item> - </el-descriptions> - </ContentWrap> - - <!-- 鍚勭鎿嶄綔鐨勫脊绐� --> - <OrderDeliveryForm ref="deliveryFormRef" @success="getDetail" /> - <OrderUpdateRemarkForm ref="updateRemarkForm" @success="getDetail" /> - <OrderUpdateAddressForm ref="updateAddressFormRef" @success="getDetail" /> - <OrderUpdatePriceForm ref="updatePriceFormRef" @success="getDetail" /> -</template> -<script lang="ts" setup> -import * as TradeOrderApi from '@/api/mall/trade/order' -import { fenToYuan } from '@/utils' -import { formatDate } from '@/utils/formatTime' -import { DICT_TYPE, getDictLabel, getDictObj } from '@/utils/dict' -import OrderUpdateRemarkForm from '@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue' -import OrderDeliveryForm from '@/views/mall/trade/order/form/OrderDeliveryForm.vue' -import OrderUpdateAddressForm from '@/views/mall/trade/order/form/OrderUpdateAddressForm.vue' -import OrderUpdatePriceForm from '@/views/mall/trade/order/form/OrderUpdatePriceForm.vue' -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' -import { useTagsViewStore } from '@/store/modules/tagsView' -import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants' -import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import { propTypes } from '@/utils/propTypes' - -defineOptions({ name: 'TradeOrderDetail' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -/** 鑾峰緱 userType 棰滆壊 */ -const getUserTypeColor = (type: number) => { - const dict = getDictObj(DICT_TYPE.USER_TYPE, type) - switch (dict?.colorType) { - case 'success': - return '#67C23A' - case 'info': - return '#909399' - case 'warning': - return '#E6A23C' - case 'danger': - return '#F56C6C' - } - return '#409EFF' -} - -// 璁㈠崟璇︽儏 -const formData = ref<TradeOrderApi.OrderVO>({ - logs: [] -}) - -/** 鍚勭鎿嶄綔 */ -const updateRemarkForm = ref() // 璁㈠崟澶囨敞琛ㄥ崟 Ref -const remark = () => { - updateRemarkForm.value?.open(formData.value) -} -const deliveryFormRef = ref() // 鍙戣揣琛ㄥ崟 Ref -const delivery = () => { - deliveryFormRef.value?.open(formData.value) -} -const updateAddressFormRef = ref() // 鏀惰揣鍦板潃琛ㄥ崟 Ref -const updateAddress = () => { - updateAddressFormRef.value?.open(formData.value) -} -const updatePriceFormRef = ref() // 璁㈠崟璋冧环琛ㄥ崟 Ref -const updatePrice = () => { - updatePriceFormRef.value?.open(formData.value) -} - -/** 鏍搁攢 */ -const handlePickUp = async () => { - try { - // 浜屾纭 - await message.confirm('纭鏍搁攢璁㈠崟鍚楋紵') - // 鎻愪氦 - await TradeOrderApi.pickUpOrder(formData.value.id!) - message.success('鏍搁攢鎴愬姛') - // 鍒锋柊鍒楄〃 - await getDetail() - } catch {} -} - -/** 鑾峰緱璇︽儏 */ -const { params } = useRoute() // 鏌ヨ鍙傛暟 -const props = defineProps({ - id: propTypes.number.def(undefined), // 璁㈠崟ID - showPickUp: propTypes.bool.def(true) // 鏄剧ず鏍搁攢鎸夐挳 -}) -const id = (params.id || props.id) as unknown as number -const getDetail = async () => { - if (id) { - const res = (await TradeOrderApi.getOrder(id)) as TradeOrderApi.OrderVO - // 娌℃湁琛ㄥ崟淇℃伅鍒欏叧闂〉闈㈣繑鍥� - if (!res) { - message.error('浜ゆ槗璁㈠崟涓嶅瓨鍦�') - close() - } - formData.value = res - } -} - -/** 鍏抽棴 tag */ -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const { push, currentRoute } = useRouter() // 璺敱 -const close = () => { - delView(unref(currentRoute)) - push({ name: 'TradeOrder' }) -} - -/** 澶嶅埗 */ -const clipboardSuccess = () => { - message.success('澶嶅埗鎴愬姛') -} - -/** 鍒濆鍖� **/ -const deliveryExpressList = ref([]) // 鐗╂祦鍏徃 -const expressTrackList = ref([]) // 鐗╂祦璇︽儏 -const pickUpStore = ref({}) // 鑷彁闂ㄥ簵 -onMounted(async () => { - await getDetail() - // 濡傛灉閰嶉�佹柟寮忎负蹇�掞紝鍒欐煡璇㈢墿娴佸叕鍙� - if (formData.value.deliveryType === DeliveryTypeEnum.EXPRESS.type) { - deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() - if (form.value.logisticsId) { - expressTrackList.value = await TradeOrderApi.getExpressTrackList(formData.value.id!) - } - } else if (formData.value.deliveryType === DeliveryTypeEnum.PICK_UP.type) { - pickUpStore.value = await DeliveryPickUpStoreApi.getDeliveryPickUpStore( - formData.value.pickUpStoreId - ) - } -}) -</script> -<style lang="scss" scoped> -:deep(.el-descriptions) { - &:not(:nth-child(1)) { - margin-top: 20px; - } - - .el-descriptions__title { - display: flex; - align-items: center; - - &::before { - display: inline-block; - width: 3px; - height: 20px; - margin-right: 10px; - background-color: #409eff; - content: ''; - } - } - - .el-descriptions-item__container { - margin: 0 10px; - - .no-colon { - margin: 0; - - &::after { - content: ''; - } - } - } -} - -// 鏃堕棿绾挎牱寮忚皟鏁� -:deep(.el-timeline) { - margin: 10px 0 0 160px; - - .el-timeline-item__wrapper { - position: relative; - top: -20px; - - .el-timeline-item__timestamp { - position: absolute !important; - top: 10px; - left: -150px; - } - } - - .el-timeline-right-content { - display: flex; - align-items: center; - min-height: 30px; - padding: 10px; - background-color: #f7f8fa; - - &::before { - position: absolute; - top: 10px; - left: 13px; /* 灏嗕吉鍏冪礌姘村钩灞呬腑 */ - border-color: transparent #f7f8fa transparent transparent; /* 灏栬棰滆壊锛屽乏渚ф湞鍚� */ - border-style: solid; - border-width: 8px; /* 璋冩暣灏栬澶у皬 */ - content: ''; /* 蹇呴』璁剧疆 content 灞炴�� */ - } - } - - .dot-node-style { - position: absolute; - left: -5px; - display: flex; - width: 20px; - height: 20px; - font-size: 10px; - color: #fff; - border-radius: 50%; - justify-content: center; - align-items: center; - } -} -</style> diff --git a/src/views/mall/trade/order/form/OrderDeliveryForm.vue b/src/views/mall/trade/order/form/OrderDeliveryForm.vue deleted file mode 100644 index 3b98c2e..0000000 --- a/src/views/mall/trade/order/form/OrderDeliveryForm.vue +++ /dev/null @@ -1,99 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="璁㈠崟鍙戣揣" width="25%"> - <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px"> - <el-form-item label="鍙戣揣鏂瑰紡"> - <el-radio-group v-model="expressType"> - <el-radio border label="express">蹇�掔墿娴�</el-radio> - <el-radio border label="none">鏃犻渶鍙戣揣</el-radio> - </el-radio-group> - </el-form-item> - <template v-if="expressType === 'express'"> - <el-form-item label="鐗╂祦鍏徃"> - <el-select v-model="formData.logisticsId" placeholder="璇烽�夋嫨" style="width: 100%"> - <el-option - v-for="item in deliveryExpressList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item label="鐗╂祦鍗曞彿"> - <el-input v-model="formData.logisticsNo" /> - </el-form-item> - </template> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' -import * as TradeOrderApi from '@/api/mall/trade/order' -import { copyValueToTarget } from '@/utils' - -defineOptions({ name: 'OrderDeliveryForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const expressType = ref('express') // 濡傛灉鍊兼槸 express锛屽垯鏄揩閫掞紱none 鍒欐槸鏃狅紱鏈潵鍋氬悓鍩庨厤閫侊紱 -const formData = ref<TradeOrderApi.DeliveryVO>({ - id: undefined, // 璁㈠崟缂栧彿 - logisticsId: null, // 鐗╂祦鍏徃缂栧彿 - logisticsNo: '' // 鐗╂祦缂栧彿 -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (row: TradeOrderApi.OrderVO) => { - resetForm() - // 璁剧疆鏁版嵁 - copyValueToTarget(formData.value, row) - if (row.logisticsId === 0) { - expressType.value = 'none' - } - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = unref(formData) - if (expressType.value === 'none') { - // 鏃犻渶鍙戣揣鐨勬儏鍐� - data.logisticsId = 0 - data.logisticsNo = '' - } - await TradeOrderApi.deliveryOrder(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, // 璁㈠崟缂栧彿 - logisticsId: null, // 鐗╂祦鍏徃缂栧彿 - logisticsNo: '' // 鐗╂祦缂栧彿 - } - formRef.value?.resetFields() -} -const deliveryExpressList = ref([]) -onMounted(async () => { - deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() -}) -</script> diff --git a/src/views/mall/trade/order/form/OrderPickUpForm.vue b/src/views/mall/trade/order/form/OrderPickUpForm.vue deleted file mode 100644 index 529263c..0000000 --- a/src/views/mall/trade/order/form/OrderPickUpForm.vue +++ /dev/null @@ -1,108 +0,0 @@ -<template> - <!-- 鏍搁攢瀵硅瘽妗� --> - <Dialog v-model="dialogVisible" title="璁㈠崟鏍搁攢" width="35%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="100px" - > - <el-form-item prop="pickUpVerifyCode" label="鏍搁攢鐮�"> - <el-input v-model="formData.pickUpVerifyCode" placeholder="璇疯緭鍏ユ牳閿�鐮�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button type="primary" :disabled="formLoading" @click="getOrderByPickUpVerifyCode"> - 鏌ヨ - </el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - <!-- 鏍搁攢纭瀵硅瘽妗� --> - <Dialog v-model="detailDialogVisible" title="璁㈠崟璇︽儏" width="55%"> - <TradeOrderDetail v-if="orderDetails.id" :id="orderDetails.id" :show-pick-up="false" /> - <template #footer> - <el-button type="primary" :disabled="formLoading" @click="submitForm"> 纭鏍搁攢 </el-button> - <el-button @click="detailDialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TradeOrderApi from '@/api/mall/trade/order' -import { OrderVO } from '@/api/mall/trade/order' -import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants' -import TradeOrderDetail from '@/views/mall/trade/order/detail/index.vue' - -/** 璁㈠崟鏍搁攢琛ㄥ崟 */ -defineOptions({ name: 'OrderPickUpForm' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const detailDialogVisible = ref(false) // 璇︽儏寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formRules = reactive({ - pickUpVerifyCode: [{ required: true, message: '鏍搁攢鐮佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formData = ref({ - pickUpVerifyCode: '' // 鏍搁攢鐮� -}) -const formRef = ref() // 琛ㄥ崟 Ref -const orderDetails = ref<OrderVO>({}) - -/** 鎵撳紑寮圭獥 */ -const open = async () => { - resetForm() - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await TradeOrderApi.pickUpOrderByVerifyCode(formData.value.pickUpVerifyCode) - message.success('鏍搁攢鎴愬姛') - detailDialogVisible.value = false - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - pickUpVerifyCode: '' // 鏍搁攢鐮� - } - formRef.value?.resetFields() -} - -/** 鏌ヨ鏍搁攢鐮佸搴旂殑璁㈠崟 */ -const getOrderByPickUpVerifyCode = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - - formLoading.value = true - const data = await TradeOrderApi.getOrderByPickUpVerifyCode(formData.value.pickUpVerifyCode) - formLoading.value = false - if (data?.deliveryType !== DeliveryTypeEnum.PICK_UP.type) { - message.error('璇疯緭鍏ユ纭殑鏍搁攢鐮�') - return - } - if (data?.status !== TradeOrderStatusEnum.UNDELIVERED.status) { - message.error('璁㈠崟涓嶆槸寰呮牳閿�鐘舵��') - return - } - orderDetails.value = data - // 鏄剧ず璇︽儏瀵硅瘽妗� - detailDialogVisible.value = true -} -</script> diff --git a/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue b/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue deleted file mode 100644 index baedb4a..0000000 --- a/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue +++ /dev/null @@ -1,98 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="淇敼璁㈠崟鏀惰揣鍦板潃" width="35%"> - <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="120px"> - <el-form-item label="鏀朵欢浜�"> - <el-input v-model="formData.receiverName" placeholder="璇疯緭鍏ユ敹浠朵汉鍚嶇О" /> - </el-form-item> - <el-form-item label="鎵嬫満鍙�"> - <el-input v-model="formData.receiverMobile" placeholder="璇疯緭鍏ユ敹浠朵汉鎵嬫満鍙�" /> - </el-form-item> - <el-form-item label="鎵�鍦ㄥ湴"> - <el-tree-select - v-model="formData.receiverAreaId" - :data="areaList" - :props="defaultProps" - :render-after-expand="true" - /> - </el-form-item> - <el-form-item label="璇︾粏鍦板潃"> - <el-input - v-model="formData.receiverDetailAddress" - :rows="3" - placeholder="璇疯緭鍏ユ敹浠朵汉璇︾粏鍦板潃" - type="textarea" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TradeOrderApi from '@/api/mall/trade/order' -import { getAreaTree } from '@/api/system/area' -import { copyValueToTarget } from '@/utils' -import { defaultProps } from '@/utils/tree' - -defineOptions({ name: 'OrderUpdateAddressForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, // 璁㈠崟缂栧彿 - receiverName: '', // 鏀朵欢浜哄悕绉� - receiverMobile: '', // 鏀朵欢浜烘墜鏈� - receiverAreaId: null, //鏀朵欢浜哄湴鍖虹紪鍙� - receiverDetailAddress: '' //鏀朵欢浜鸿缁嗗湴鍧� -}) -const areaList = ref([]) // 鍦板尯鍒楄〃 -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (row: TradeOrderApi.OrderVO) => { - resetForm() - // 璁剧疆鏁版嵁 - copyValueToTarget(formData.value, row) - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = unref(formData) - await TradeOrderApi.updateOrderAddress(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, // 璁㈠崟缂栧彿 - receiverName: '', // 鏀朵欢浜哄悕绉� - receiverMobile: '', // 鏀朵欢浜烘墜鏈� - receiverAreaId: null, //鏀朵欢浜哄湴鍖虹紪鍙� - receiverDetailAddress: '' //鏀朵欢浜鸿缁嗗湴鍧� - } - formRef.value?.resetFields() -} - -onMounted(async () => { - // 鑾峰緱鍦板尯鍒楄〃 - areaList.value = await getAreaTree() -}) -</script> diff --git a/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue b/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue deleted file mode 100644 index 8332e31..0000000 --- a/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue +++ /dev/null @@ -1,95 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="璁㈠崟璋冧环" width="25%"> - <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="100px"> - <el-form-item label="搴斾粯閲戦(鎬�)"> - <el-input v-model="formData.payPrice" disabled /> - </el-form-item> - <el-form-item label="璁㈠崟璋冧环"> - <el-input-number v-model="formData.adjustPrice" :precision="2" :step="0.1" class="w-100%" /> - <el-tag class="ml-10px" type="warning">璁㈠崟璋冧环銆� 姝f暟锛屽姞浠凤紱璐熸暟锛屽噺浠�</el-tag> - </el-form-item> - <el-form-item label="璋冧环鍚�"> - <el-input v-model="formData.newPayPrice" disabled /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TradeOrderApi from '@/api/mall/trade/order' -import { convertToInteger, floatToFixed2, formatToFraction } from '@/utils' -import { cloneDeep } from 'lodash-es' - -defineOptions({ name: 'OrderUpdatePriceForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, // 璁㈠崟缂栧彿 - adjustPrice: 0, // 璁㈠崟璋冧环 - payPrice: '', // 搴斾粯閲戦(鎬�) - newPayPrice: '' // 璋冧环鍚庡簲浠橀噾棰�(鎬�) -}) -watch( - () => formData.value.adjustPrice, - (adjustPrice: number | string) => { - const numMatch = formData.value.payPrice.match(/\d+(\.\d+)?/) - if (numMatch) { - const payPriceNum = parseFloat(numMatch[0]) - adjustPrice = typeof adjustPrice === 'string' ? parseFloat(adjustPrice) : adjustPrice - formData.value.newPayPrice = (payPriceNum + adjustPrice).toFixed(2) + '鍏�' - } - } -) - -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (row: TradeOrderApi.OrderVO) => { - resetForm() - formData.value.id = row.id! - // 璁剧疆鏁版嵁 - formData.value.adjustPrice = formatToFraction(row.adjustPrice!) - formData.value.payPrice = floatToFixed2(row.payPrice!) + '鍏�' - formData.value.newPayPrice = formData.value.payPrice - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = cloneDeep(unref(formData)) - data.adjustPrice = convertToInteger(data.adjustPrice) - delete data.payPrice - delete data.newPayPrice - await TradeOrderApi.updateOrderPrice(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, // 璁㈠崟缂栧彿 - adjustPrice: 0, // 璁㈠崟璋冧环 - payPrice: '', // 搴斾粯閲戦(鎬�) - newPayPrice: '' // 璋冧环鍚庡簲浠橀噾棰�(鎬�) - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue b/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue deleted file mode 100644 index e979501..0000000 --- a/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="鍟嗗澶囨敞" width="45%"> - <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px"> - <el-form-item label="澶囨敞"> - <el-input - v-model="formData.remark" - :rows="3" - placeholder="璇疯緭鍏ヨ鍗曞娉�" - type="textarea" - /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as TradeOrderApi from '@/api/mall/trade/order' - -defineOptions({ name: 'OrderUpdateRemarkForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, // 璁㈠崟缂栧彿 - remark: '' // 璁㈠崟澶囨敞 -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (row: TradeOrderApi.OrderVO) => { - resetForm() - // 璁剧疆鏁版嵁 - formData.value.id = row.id - formData.value.remark = row.remark - dialogVisible.value = true -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = unref(formData) - await TradeOrderApi.updateOrderRemark(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success', true) - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, // 璁㈠崟缂栧彿 - remark: '' // 璁㈠崟澶囨敞 - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/mall/trade/order/index.vue b/src/views/mall/trade/order/index.vue deleted file mode 100644 index 56aa57b..0000000 --- a/src/views/mall/trade/order/index.vue +++ /dev/null @@ -1,357 +0,0 @@ -<template> - <doc-alert title="銆愪氦鏄撱�戜氦鏄撹鍗�" url="https://doc.iocoder.cn/mall/trade-order/" /> - <doc-alert title="銆愪氦鏄撱�戣喘鐗╄溅" url="https://doc.iocoder.cn/mall/trade-cart/" /> - - <!-- 鎼滅储 --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="璁㈠崟鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鏀粯鏂瑰紡" prop="payChannelCode"> - <el-select - v-model="queryParams.payChannelCode" - class="!w-280px" - clearable - placeholder="鍏ㄩ儴" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-280px" - end-placeholder="鑷畾涔夋椂闂�" - start-placeholder="鑷畾涔夋椂闂�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="璁㈠崟鏉ユ簮" prop="terminal"> - <el-select v-model="queryParams.terminal" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟绫诲瀷" prop="type"> - <el-select v-model="queryParams.type" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="閰嶉�佹柟寮�" prop="deliveryType"> - <el-select v-model="queryParams.deliveryType" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type" - label="蹇�掑叕鍙�" - prop="logisticsId" - > - <el-select v-model="queryParams.logisticsId" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="item in deliveryExpressList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" - label="鑷彁闂ㄥ簵" - prop="pickUpStoreId" - > - <el-select - v-model="queryParams.pickUpStoreId" - class="!w-280px" - clearable - multiple - placeholder="鍏ㄩ儴" - > - <el-option - v-for="item in pickUpStoreList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" - label="鏍搁攢鐮�" - prop="pickUpVerifyCode" - > - <el-input - v-model="queryParams.pickUpVerifyCode" - class="!w-280px" - clearable - placeholder="璇疯緭鍏ヨ嚜鎻愭牳閿�鐮�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鑱氬悎鎼滅储"> - <el-input - v-show="true" - v-model="queryParams[queryType.queryParam]" - :type="queryType.queryParam === 'userId' ? 'number' : 'text'" - class="!w-280px" - clearable - placeholder="璇疯緭鍏�" - > - <template #prepend> - <el-select - v-model="queryType.queryParam" - class="!w-110px" - clearable - placeholder="鍏ㄩ儴" - @change="inputChangeSelect" - > - <el-option - v-for="dict in dynamicSearchList" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </template> - </el-input> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <!-- 娣诲姞 row-key="id" 瑙e喅鍒楁暟鎹腑鐨� table#header 鏁版嵁涓嶅埛鏂扮殑闂 --> - <el-table v-loading="loading" :data="list" row-key="id"> - <OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList"> - <template #default="{ row }"> - <div class="flex items-center justify-center"> - <el-button - v-hasPermi="['trade:order:query']" - link - type="primary" - @click="openDetail(row.id)" - > - <Icon icon="ep:notification" /> - 璇︽儏 - </el-button> - <el-dropdown - v-hasPermi="['trade:order:update']" - @command="(command) => handleCommand(command, row)" - > - <el-button link type="primary"> - <Icon icon="ep:d-arrow-right" /> - 鏇村 - </el-button> - <template #dropdown> - <el-dropdown-menu> - <!-- 濡傛灉鏄�愬揩閫掋�戯紝骞朵笖銆愭湭鍙戣揣銆戯紝鍒欏睍绀恒�愬彂璐с�戞寜閽� --> - <el-dropdown-item - v-if=" - row.deliveryType === DeliveryTypeEnum.EXPRESS.type && - row.status === TradeOrderStatusEnum.UNDELIVERED.status - " - command="delivery" - > - <Icon icon="ep:takeaway-box" /> - 鍙戣揣 - </el-dropdown-item> - <el-dropdown-item command="remark"> - <Icon icon="ep:chat-line-square" /> - 澶囨敞 - </el-dropdown-item> - </el-dropdown-menu> - </template> - </el-dropdown> - </div> - </template> - </OrderTableColumn> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 鍚勭鎿嶄綔鐨勫脊绐� --> - <OrderDeliveryForm ref="deliveryFormRef" @success="getList" /> - <OrderUpdateRemarkForm ref="updateRemarkForm" @success="getList" /> -</template> - -<script lang="ts" setup> -import type { FormInstance } from 'element-plus' -import OrderDeliveryForm from '@/views/mall/trade/order/form/OrderDeliveryForm.vue' -import OrderUpdateRemarkForm from '@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue' -import * as TradeOrderApi from '@/api/mall/trade/order' -import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' -import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants' -import { OrderTableColumn } from './components' - -defineOptions({ name: 'TradeOrder' }) - -const { currentRoute, push } = useRouter() // 璺敱璺宠浆 -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(2) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref<TradeOrderApi.OrderVO[]>([]) // 鍒楄〃鐨勬暟鎹� -const queryFormRef = ref<FormInstance>() // 鎼滅储鐨勮〃鍗� -// 琛ㄥ崟鎼滅储 -const queryParams = ref({ - pageNo: 1, // 椤垫暟 - pageSize: 10, // 姣忛〉鏄剧ず鏁伴噺 - status: undefined, // 璁㈠崟鐘舵�� - payChannelCode: undefined, // 鏀粯鏂瑰紡 - createTime: undefined, // 鍒涘缓鏃堕棿 - terminal: undefined, // 璁㈠崟鏉ユ簮 - type: undefined, // 璁㈠崟绫诲瀷 - deliveryType: undefined, // 閰嶉�佹柟寮� - logisticsId: undefined, // 蹇�掑叕鍙� - pickUpStoreId: undefined, // 鑷彁闂ㄥ簵 - pickUpVerifyCode: undefined // 鑷彁鏍搁攢鐮� -}) -const queryType = reactive({ queryParam: '' }) // 璁㈠崟鎼滅储绫诲瀷 queryParam - -// 璁㈠崟鑱氬悎鎼滅储 select 绫诲瀷閰嶇疆锛堝姩鎬佹悳绱級 -const dynamicSearchList = ref([ - { value: 'no', label: '璁㈠崟鍙�' }, - { value: 'userId', label: '鐢ㄦ埛UID' }, - { value: 'userNickname', label: '鐢ㄦ埛鏄电О' }, - { value: 'userMobile', label: '鐢ㄦ埛鐢佃瘽' } -]) -/** - * 鑱氬悎鎼滅储鍒囨崲鏌ヨ瀵硅薄鏃惰Е鍙� - * @param val - */ -const inputChangeSelect = (val: string) => { - dynamicSearchList.value - .filter((item) => item.value !== val) - ?.forEach((item1) => { - // 娓呴櫎闆嗗悎鎼滅储鏃犵敤灞炴�� - if (queryParams.value.hasOwnProperty(item1.value)) { - delete queryParams.value[item1.value] - } - }) -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TradeOrderApi.getOrderPage(unref(queryParams)) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = async () => { - queryParams.value.pageNo = 1 - await getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - queryParams.value = { - pageNo: 1, // 椤垫暟 - pageSize: 10, // 姣忛〉鏄剧ず鏁伴噺 - status: undefined, // 璁㈠崟鐘舵�� - payChannelCode: undefined, // 鏀粯鏂瑰紡 - createTime: undefined, // 鍒涘缓鏃堕棿 - terminal: undefined, // 璁㈠崟鏉ユ簮 - type: undefined, // 璁㈠崟绫诲瀷 - deliveryType: undefined, // 閰嶉�佹柟寮� - logisticsId: undefined, // 蹇�掑叕鍙� - pickUpStoreId: undefined, // 鑷彁闂ㄥ簵 - pickUpVerifyCode: undefined // 鑷彁鏍搁攢鐮� - } - handleQuery() -} - -/** 鏌ョ湅璁㈠崟璇︽儏 */ -const openDetail = (id: number) => { - push({ name: 'TradeOrderDetail', params: { id } }) -} - -/** 鎿嶄綔鍒嗗彂 */ -const deliveryFormRef = ref() -const updateRemarkForm = ref() -const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => { - switch (command) { - case 'remark': - updateRemarkForm.value?.open(row) - break - case 'delivery': - deliveryFormRef.value?.open(row) - break - } -} - -// 鐩戝惉璺敱鍙樺寲鏇存柊鍒楄〃锛岃В鍐宠鍗曚繚瀛�/鏇存柊鍚庯紝鍒楄〃涓嶅埛鏂扮殑闂銆� -watch( - () => currentRoute.value, - () => { - getList() - } -) - -const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 鑷彁闂ㄥ簵绮剧畝鍒楄〃 -const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 鐗╂祦鍏徃 -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - pickUpStoreList.value = await PickUpStoreApi.getListAllSimple() - deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() -}) -</script> diff --git a/src/views/member/config/index.vue b/src/views/member/config/index.vue deleted file mode 100644 index 2593509..0000000 --- a/src/views/member/config/index.vue +++ /dev/null @@ -1,121 +0,0 @@ -<template> - <doc-alert title="浼氬憳鎵嬪唽锛堝姛鑳藉紑鍚級" url="https://doc.iocoder.cn/member/build/" /> - - <ContentWrap> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="hideId" v-show="false"> - <el-input v-model="formData.id" /> - </el-form-item> - - <el-tabs> - <el-tab-pane label="绉垎"> - <el-form-item label="绉垎鎶垫墸" prop="pointTradeDeductEnable"> - <el-switch v-model="formData.pointTradeDeductEnable" style="user-select: none" /> - <el-text class="w-full" size="small" type="info">涓嬪崟绉垎鏄惁鎶电敤璁㈠崟閲戦</el-text> - </el-form-item> - <el-form-item label="绉垎鎶垫墸" prop="pointTradeDeductUnitPrice"> - <el-input-number - v-model="computedPointTradeDeductUnitPrice" - placeholder="璇疯緭鍏ョН鍒嗘姷鎵i噾棰�" - :precision="2" - /> - <el-text class="w-full" size="small" type="info"> - 绉垎鎶电敤姣斾緥(1 绉垎鎶靛灏戦噾棰�)锛屽崟浣嶏細鍏� - </el-text> - </el-form-item> - <el-form-item label="绉垎鎶垫墸鏈�澶у��" prop="pointTradeDeductMaxPrice"> - <el-input-number - v-model="formData.pointTradeDeductMaxPrice" - placeholder="璇疯緭鍏ョН鍒嗘姷鎵f渶澶у��" - /> - <el-text class="w-full" size="small" type="info"> - 鍗曟涓嬪崟绉垎浣跨敤涓婇檺锛�0 涓嶉檺鍒� - </el-text> - </el-form-item> - <el-form-item label="1 鍏冭禒閫佸灏戝垎" prop="pointTradeGivePoint"> - <el-input-number - v-model="formData.pointTradeGivePoint" - placeholder="璇疯緭鍏� 1 鍏冭禒閫佸灏戠Н鍒�" - /> - <el-text class="w-full" size="small" type="info"> - 涓嬪崟鏀粯閲戦鎸夋瘮渚嬭禒閫佺Н鍒嗭紙瀹為檯鏀粯 1 鍏冭禒閫佸灏戠Н鍒嗭級 - </el-text> - </el-form-item> - </el-tab-pane> - </el-tabs> - - <el-form-item> - <el-button type="primary" @click="onSubmit">淇濆瓨</el-button> - </el-form-item> - </el-form> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as ConfigApi from '@/api/member/config' - -defineOptions({ name: 'MemberConfig' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - pointTradeDeductEnable: true, - pointTradeDeductUnitPrice: 0, - pointTradeDeductMaxPrice: 0, - pointTradeGivePoint: 0 -}) - -// 鍒涘缓涓�涓绠楀睘鎬э紝鐢ㄤ簬灏� pointTradeDeductUnitPrice 鏄剧ず涓哄甫涓や綅灏忔暟鐨勫舰寮� -const computedPointTradeDeductUnitPrice = computed({ - get: () => (formData.value.pointTradeDeductUnitPrice / 100).toFixed(2), - set: (newValue: number) => { - formData.value.pointTradeDeductUnitPrice = Math.round(newValue * 100) - } -}) - -const formRules = reactive({}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 淇敼绉垎閰嶇疆 */ -const onSubmit = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as ConfigApi.ConfigVO - await ConfigApi.saveConfig(data) - message.success(t('common.updateSuccess')) - dialogVisible.value = false - } finally { - formLoading.value = false - } -} - -/** 鑾峰緱绉垎閰嶇疆 */ -const getConfig = async () => { - try { - const data = await ConfigApi.getConfig() - if (data === null) { - return - } - formData.value = data - } finally { - } -} - -onMounted(() => { - getConfig() -}) -</script> diff --git a/src/views/member/group/GroupForm.vue b/src/views/member/group/GroupForm.vue deleted file mode 100644 index 14510b0..0000000 --- a/src/views/member/group/GroupForm.vue +++ /dev/null @@ -1,112 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="600"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ悕绉�" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as GroupApi from '@/api/member/group' -import { CommonStatusEnum } from '@/utils/constants' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - remark: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await GroupApi.getGroup(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as GroupApi.GroupVO - if (formType.value === 'create') { - await GroupApi.createGroup(data) - message.success(t('common.createSuccess')) - } else { - await GroupApi.updateGroup(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - remark: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/group/components/MemberGroupSelect.vue b/src/views/member/group/components/MemberGroupSelect.vue deleted file mode 100644 index 78a993a..0000000 --- a/src/views/member/group/components/MemberGroupSelect.vue +++ /dev/null @@ -1,45 +0,0 @@ -<template> - <el-select v-model="groupId" placeholder="璇烽�夋嫨鐢ㄦ埛鍒嗙粍" clearable class="!w-240px"> - <el-option - v-for="group in groupOptions" - :key="group.id" - :label="group.name" - :value="group.id" - /> - </el-select> -</template> -<script lang="ts" setup> -import * as GroupApi from '@/api/member/group' - -/** 浼氬憳鍒嗙粍閫夋嫨妗� **/ -defineOptions({ name: 'MemberGroupSelect' }) - -const props = defineProps({ - /** 涓嬫媺妗嗛�変腑鍊� **/ - modelValue: { - type: Number, - default: undefined - } -}) -const emit = defineEmits(['update:modelValue']) - -const groupId = computed({ - get() { - return props.modelValue - }, - set(value: any) { - emit('update:modelValue', value) - } -}) - -const groupOptions = ref<GroupApi.GroupVO[]>([]) - -const getList = async () => { - groupOptions.value = await GroupApi.getSimpleGroupList() -} - -/** 鍒濆鍖� */ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/group/index.vue b/src/views/member/group/index.vue deleted file mode 100644 index ba925d6..0000000 --- a/src/views/member/group/index.vue +++ /dev/null @@ -1,176 +0,0 @@ -<template> - <doc-alert title="浼氬憳鐢ㄦ埛銆佹爣绛俱�佸垎缁�" url="https://doc.iocoder.cn/member/user/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鍒嗙粍鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ垎缁勫悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" @click="openForm('create')" v-hasPermi="['member:group:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" min-width="60" /> - <el-table-column label="鍚嶇О" align="center" prop="name" min-width="80" /> - <el-table-column label="澶囨敞" align="center" prop="remark" min-width="100" /> - <el-table-column label="鐘舵��" align="center" prop="status" min-width="70"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - min-width="170" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['member:group:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['member:group:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <GroupForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as GroupApi from '@/api/member/group' -import GroupForm from './GroupForm.vue' - -/** 鐢ㄦ埛鍒嗙粍绠$悊 **/ -defineOptions({ name: 'MemberGroup' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await GroupApi.getGroupPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await GroupApi.deleteGroup(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/level/LevelForm.vue b/src/views/member/level/LevelForm.vue deleted file mode 100644 index 7e6873c..0000000 --- a/src/views/member/level/LevelForm.vue +++ /dev/null @@ -1,175 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="800"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="110px" - v-loading="formLoading" - > - <el-row> - <el-col :span="12"> - <el-form-item label="绛夌骇鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ瓑绾у悕绉�" class="!w-240px" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="绛夌骇" prop="level"> - <el-input-number - v-model="formData.level" - :min="0" - :precision="0" - placeholder="璇疯緭鍏ョ瓑绾�" - class="!w-240px" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="鍗囩骇缁忛獙" prop="experience"> - <el-input-number - v-model="formData.experience" - :min="0" - :precision="0" - placeholder="璇疯緭鍏ュ崌绾х粡楠�" - class="!w-240px" - /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="浜彈鎶樻墸(%)" prop="discountPercent"> - <el-input-number - v-model="formData.discountPercent" - :min="0" - :max="100" - :precision="0" - placeholder="璇疯緭鍏ヤ韩鍙楁姌鎵�" - class="!w-240px" - /> - </el-form-item> - </el-col> - </el-row> - <el-row> - <el-col :span="12"> - <el-form-item label="绛夌骇鍥炬爣"> - <UploadImg v-model="formData.icon" /> - </el-form-item> - </el-col> - <el-col :span="12"> - <el-form-item label="鑳屾櫙鍥�"> - <UploadImg v-model="formData.backgroundUrl" /> - </el-form-item> - </el-col> - </el-row> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as LevelApi from '@/api/member/level' -import { CommonStatusEnum } from '@/utils/constants' - -/** 浼氬憳绛夌骇琛ㄥ崟 **/ -defineOptions({ name: 'MemberLevelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - experience: undefined, - level: undefined, - discountPercent: undefined, - icon: undefined, - backgroundUrl: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '绛夌骇鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }], - experience: [{ required: true, message: '鍗囩骇缁忛獙涓嶈兘涓虹┖', trigger: 'blur' }], - level: [{ required: true, message: '绛夌骇涓嶈兘涓虹┖', trigger: 'blur' }], - discountPercent: [{ required: true, message: '浜彈鎶樻墸涓嶈兘涓虹┖', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'change' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await LevelApi.getLevel(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as LevelApi.LevelVO - if (formType.value === 'create') { - await LevelApi.createLevel(data) - message.success(t('common.createSuccess')) - } else { - await LevelApi.updateLevel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - experience: undefined, - level: undefined, - discountPercent: undefined, - icon: undefined, - backgroundUrl: undefined, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/level/components/MemberLevelSelect.vue b/src/views/member/level/components/MemberLevelSelect.vue deleted file mode 100644 index 2a603e6..0000000 --- a/src/views/member/level/components/MemberLevelSelect.vue +++ /dev/null @@ -1,45 +0,0 @@ -<template> - <el-select v-model="levelId" placeholder="璇烽�夋嫨鐢ㄦ埛绛夌骇" clearable class="!w-240px"> - <el-option v-for="level in levelOptions" :key="level.id" :label="level.name" :value="level.id"> - <span class="flex items-center gap-x-8px"> - <el-avatar :src="level.icon" size="small" /> - {{ level.name }} - </span> - </el-option> - </el-select> -</template> -<script lang="ts" setup> -import * as LevelApi from '@/api/member/level' - -/** 浼氬憳绛夌骇閫夋嫨妗� **/ -defineOptions({ name: 'MemberLevelSelect' }) - -const props = defineProps({ - /** 涓嬫媺妗嗛�変腑鍊� **/ - modelValue: { - type: Number, - default: undefined - } -}) -const emit = defineEmits(['update:modelValue']) - -const levelId = computed({ - get() { - return props.modelValue - }, - set(value: any) { - emit('update:modelValue', value) - } -}) - -const levelOptions = ref<LevelApi.LevelVO[]>([]) - -const getList = async () => { - levelOptions.value = await LevelApi.getSimpleLevelList() -} - -/** 鍒濆鍖� */ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/level/index.vue b/src/views/member/level/index.vue deleted file mode 100644 index 3743eac..0000000 --- a/src/views/member/level/index.vue +++ /dev/null @@ -1,171 +0,0 @@ -<template> - <doc-alert title="浼氬憳绛夌骇銆佺Н鍒嗐�佺鍒�" url="https://doc.iocoder.cn/member/level/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="绛夌骇鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ョ瓑绾у悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" @click="openForm('create')" v-hasPermi="['member:level:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" min-width="60" /> - <el-table-column label="绛夌骇鍥炬爣" align="center" prop="icon" min-width="80"> - <template #default="scope"> - <el-image - :src="scope.row.icon" - class="h-30px w-30px" - :preview-src-list="[scope.row.icon]" - /> - </template> - </el-table-column> - <el-table-column label="绛夌骇鑳屾櫙鍥�" align="center" prop="backgroundUrl" min-width="100"> - <template #default="scope"> - <el-image - :src="scope.row.backgroundUrl" - class="h-30px w-30px" - :preview-src-list="[scope.row.backgroundUrl]" - /> - </template> - </el-table-column> - <el-table-column label="绛夌骇鍚嶇О" align="center" prop="name" min-width="100" /> - <el-table-column label="绛夌骇" align="center" prop="level" min-width="60" /> - <el-table-column label="鍗囩骇缁忛獙" align="center" prop="experience" min-width="80" /> - <el-table-column label="浜彈鎶樻墸(%)" align="center" prop="discountPercent" min-width="110" /> - <el-table-column label="鐘舵��" align="center" prop="status" min-width="70"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - min-width="170" - /> - <el-table-column label="鎿嶄綔" align="center" min-width="110px" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['member:level:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['member:level:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <LevelForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as LevelApi from '@/api/member/level' -import LevelForm from './LevelForm.vue' - -/** 浼氬憳绛夌骇绠$悊 **/ -defineOptions({ name: 'MemberLevel' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - name: null, - status: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - list.value = await LevelApi.getLevelList(queryParams) - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await LevelApi.deleteLevel(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/point/record/index.vue b/src/views/member/point/record/index.vue deleted file mode 100644 index 9676c2e..0000000 --- a/src/views/member/point/record/index.vue +++ /dev/null @@ -1,161 +0,0 @@ -<template> - <doc-alert title="浼氬憳绛夌骇銆佺Н鍒嗐�佺鍒�" url="https://doc.iocoder.cn/member/level/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛" prop="nickname"> - <el-input - v-model="queryParams.nickname" - placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="涓氬姟绫诲瀷" prop="bizType"> - <el-select - v-model="queryParams.bizType" - placeholder="璇烽�夋嫨涓氬姟绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_POINT_BIZ_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="绉垎鏍囬" prop="title"> - <el-input - v-model="queryParams.title" - placeholder="璇疯緭鍏ョН鍒嗘爣棰�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鑾峰緱鏃堕棿" prop="createDate"> - <el-date-picker - v-model="queryParams.createDate" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" width="180" /> - <el-table-column - label="鑾峰緱鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column label="鐢ㄦ埛" align="center" prop="nickname" width="200" /> - <el-table-column label="鑾峰緱绉垎" align="center" prop="point" width="100"> - <template #default="scope"> - <el-tag v-if="scope.row.point > 0" class="ml-2" type="success" effect="dark"> - +{{ scope.row.point }} - </el-tag> - <el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag> - </template> - </el-table-column> - <el-table-column label="鎬荤Н鍒�" align="center" prop="totalPoint" width="100" /> - <el-table-column label="鏍囬" align="center" prop="title" /> - <el-table-column label="鎻忚堪" align="center" prop="description" /> - <el-table-column label="涓氬姟缂栫爜" align="center" prop="bizId" /> - <el-table-column label="涓氬姟绫诲瀷" align="center" prop="bizType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.MEMBER_POINT_BIZ_TYPE" :value="scope.row.bizType" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <RecordForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as RecordApi from '@/api/member/point/record' - -defineOptions({ name: 'PointRecord' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - nickname: null, - bizType: null, - title: null, - createDate: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await RecordApi.getRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/signin/config/SignInConfigForm.vue b/src/views/member/signin/config/SignInConfigForm.vue deleted file mode 100644 index 616fd8f..0000000 --- a/src/views/member/signin/config/SignInConfigForm.vue +++ /dev/null @@ -1,132 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="绛惧埌澶╂暟" prop="day"> - <el-input-number v-model="formData.day" :min="1" :max="7" :precision="0" /> - <el-text class="mx-1" style="margin-left: 10px" type="danger"> - 鍙厑璁歌缃� 1-7锛岄粯璁ょ鍒� 7 澶╀负涓�涓懆鏈� - </el-text> - </el-form-item> - <el-form-item label="濂栧姳绉垎" prop="point"> - <el-input-number v-model="formData.point" :min="0" :precision="0" /> - </el-form-item> - <el-form-item label="濂栧姳缁忛獙" prop="experience"> - <el-input-number v-model="formData.experience" :min="0" :precision="0" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup> -import * as SignInConfigApi from '@/api/member/signin/config' -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref<SignInConfigApi.SignInConfigVO>({} as SignInConfigApi.SignInConfigVO) -// 濂栧姳鏍¢獙瑙勫垯 -const awardValidator = (rule: any, _value: any, callback: any) => { - if (!formData.value.point && !formData.value.experience) { - callback(new Error('濂栧姳绉垎涓庡鍔辩粡楠岃嚦灏戦厤缃竴涓�')) - return - } - - // 娓呴櫎鍙︿竴涓瓧娈电殑閿欒鎻愮ず - const otherAwardField = rule?.field === 'point' ? 'experience' : 'point' - formRef.value.validateField(otherAwardField, () => null) - callback() -} -const formRules = reactive({ - day: [{ required: true, message: '绛惧埌澶╂暟涓嶈兘绌�', trigger: 'blur' }], - point: [ - { required: true, message: '濂栧姳绉垎涓嶈兘绌�', trigger: 'blur' }, - { validator: awardValidator, trigger: 'blur' } - ], - experience: [ - { required: true, message: '濂栧姳缁忛獙涓嶈兘绌�', trigger: 'blur' }, - { validator: awardValidator, trigger: 'blur' } - ] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await SignInConfigApi.getSignInConfig(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - if (formType.value === 'create') { - await SignInConfigApi.createSignInConfig(formData.value) - message.success(t('common.createSuccess')) - } else { - await SignInConfigApi.updateSignInConfig(formData.value) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - day: undefined, - point: 0, - experience: 0, - status: CommonStatusEnum.ENABLE - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/signin/config/index.vue b/src/views/member/signin/config/index.vue deleted file mode 100644 index 14a84cd..0000000 --- a/src/views/member/signin/config/index.vue +++ /dev/null @@ -1,106 +0,0 @@ -<template> - <doc-alert title="浼氬憳绛夌骇銆佺Н鍒嗐�佺鍒�" url="https://doc.iocoder.cn/member/level/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['point:sign-in-config:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column - label="绛惧埌澶╂暟" - align="center" - prop="day" - :formatter="(_, __, cellValue) => ['绗�', cellValue, '澶�'].join(' ')" - /> - <el-table-column label="濂栧姳绉垎" align="center" prop="point" /> - <el-table-column label="濂栧姳缁忛獙" align="center" prop="experience" /> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['point:sign-in-config:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['point:sign-in-config:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <SignInConfigForm ref="formRef" @success="getList" /> -</template> -<script lang="ts" setup> -import * as SignInConfigApi from '@/api/member/signin/config' -import SignInConfigForm from './SignInConfigForm.vue' -import { DICT_TYPE } from '@/utils/dict' - -defineOptions({ name: 'SignInConfig' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const list = ref([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SignInConfigApi.getSignInConfigList() - console.log(data) - list.value = data - } finally { - loading.value = false - } -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await SignInConfigApi.deleteSignInConfig(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/signin/record/index.vue b/src/views/member/signin/record/index.vue deleted file mode 100644 index e80e854..0000000 --- a/src/views/member/signin/record/index.vue +++ /dev/null @@ -1,134 +0,0 @@ -<template> - <doc-alert title="浼氬憳绛夌骇銆佺Н鍒嗐�佺鍒�" url="https://doc.iocoder.cn/member/level/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="绛惧埌鐢ㄦ埛" prop="nickname"> - <el-input - v-model="queryParams.nickname" - placeholder="璇疯緭鍏ョ鍒扮敤鎴�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绛惧埌澶╂暟" prop="day"> - <el-input - v-model="queryParams.day" - placeholder="璇疯緭鍏ョ鍒板ぉ鏁�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绛惧埌鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="绛惧埌鐢ㄦ埛" align="center" prop="nickname" /> - <el-table-column - label="绛惧埌澶╂暟" - align="center" - prop="day" - :formatter="(_, __, cellValue) => ['绗�', cellValue, '澶�'].join(' ')" - /> - <el-table-column label="鑾峰緱绉垎" align="center" prop="point" width="100"> - <template #default="scope"> - <el-tag v-if="scope.row.point > 0" class="ml-2" type="success" effect="dark"> - +{{ scope.row.point }} - </el-tag> - <el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag> - </template> - </el-table-column> - <el-table-column - label="绛惧埌鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as SignInRecordApi from '@/api/member/signin/record' - -defineOptions({ name: 'SignInRecord' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - nickname: null, - day: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SignInRecordApi.getSignInRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/tag/TagForm.vue b/src/views/member/tag/TagForm.vue deleted file mode 100644 index d45ea58..0000000 --- a/src/views/member/tag/TagForm.vue +++ /dev/null @@ -1,91 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鏍囩鍚嶇О" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ユ爣绛惧悕绉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as TagApi from '@/api/member/tag' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '鏍囩鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await TagApi.getMemberTag(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as TagApi.TagVO - if (formType.value === 'create') { - await TagApi.createMemberTag(data) - message.success(t('common.createSuccess')) - } else { - await TagApi.updateMemberTag(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/tag/components/MemberTagSelect.vue b/src/views/member/tag/components/MemberTagSelect.vue deleted file mode 100644 index ebff61e..0000000 --- a/src/views/member/tag/components/MemberTagSelect.vue +++ /dev/null @@ -1,68 +0,0 @@ -<template> - <el-select v-model="tagIds" placeholder="璇烽�夋嫨鐢ㄦ埛鏍囩" clearable multiple class="!w-240px"> - <el-option v-for="tag in tags" :key="tag.id" :label="tag.name" :value="tag.id" /> - </el-select> - <el-button - v-if="showAdd" - type="primary" - class="ml-2" - link - @click="openForm('create')" - v-hasPermi="['member:tag:create']" - > - 鏂板鏍囩 - </el-button> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔� --> - <TagForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -import * as TagApi from '@/api/member/tag' -import TagForm from '@/views/member/tag/TagForm.vue' - -defineOptions({ name: 'MemberTagSelect' }) - -const props = defineProps({ - /** 涓嬫媺妗嗛�変腑鍊� **/ - modelValue: { - type: Array, - default: undefined - }, - /** 鏄惁鏄剧ず鈥滄柊澧炴爣绛锯�濇寜閽� **/ - showAdd: { - type: Boolean, - default: false - } -}) -const emit = defineEmits(['update:modelValue']) -defineExpose({ - showAdd: props.showAdd -}) - -const tagIds = computed({ - get() { - return props.modelValue - }, - set(value: any) { - emit('update:modelValue', value) - } -}) - -const tags = ref<TagApi.TagVO[]>([]) - -const getList = async () => { - tags.value = await TagApi.getSimpleTagList() -} - -/** 娣诲姞鐢ㄦ埛鏍囩琛ㄥ崟寮规 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒濆鍖� */ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/tag/index.vue b/src/views/member/tag/index.vue deleted file mode 100644 index 59efc5e..0000000 --- a/src/views/member/tag/index.vue +++ /dev/null @@ -1,155 +0,0 @@ -<template> - <doc-alert title="浼氬憳鐢ㄦ埛銆佹爣绛俱�佸垎缁�" url="https://doc.iocoder.cn/member/user/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鏍囩鍚嶇О" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ユ爣绛惧悕绉�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" @click="openForm('create')" v-hasPermi="['member:tag:create']"> - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" width="150px" /> - <el-table-column label="鏍囩鍚嶇О" align="center" prop="name" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" width="150px"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['member:tag:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['member:tag:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <TagForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts" name="MemberTag"> -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as TagApi from '@/api/member/tag' -import TagForm from './TagForm.vue' -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TagApi.getMemberTagPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await TagApi.deleteMemberTag(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/user/UserForm.vue b/src/views/member/user/UserForm.vue deleted file mode 100644 index 0da4ef6..0000000 --- a/src/views/member/user/UserForm.vue +++ /dev/null @@ -1,179 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鎵嬫満鍙�" prop="mobile"> - <el-input v-model="formData.mobile" placeholder="璇疯緭鍏ユ墜鏈哄彿" /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鐢ㄦ埛鏄电О" prop="nickname"> - <el-input v-model="formData.nickname" placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" /> - </el-form-item> - <el-form-item label="澶村儚" prop="avatar"> - <UploadImg v-model="formData.avatar" :limit="1" :is-show-tip="false" /> - </el-form-item> - <el-form-item label="鐪熷疄鍚嶅瓧" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ョ湡瀹炲悕瀛�" /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鎬у埆" prop="sex"> - <el-radio-group v-model="formData.sex"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鍑虹敓鏃ユ湡" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="閫夋嫨鍑虹敓鏃ユ湡" - /> - </el-form-item> - <el-form-item label="鎵�鍦ㄥ湴" prop="areaId"> - <el-tree-select - v-model="formData.areaId" - :data="areaList" - :props="defaultProps" - :render-after-expand="true" - /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鏍囩" prop="tagIds"> - <MemberTagSelect v-model="formData.tagIds" show-add /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鍒嗙粍" prop="groupId"> - <MemberGroupSelect v-model="formData.groupId" /> - </el-form-item> - <el-form-item label="浼氬憳澶囨敞" prop="mark"> - <el-input type="textarea" v-model="formData.mark" placeholder="璇疯緭鍏ヤ細鍛樺娉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as UserApi from '@/api/member/user' -import * as AreaApi from '@/api/system/area' -import { defaultProps } from '@/utils/tree' -import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue' -import MemberGroupSelect from '@/views/member/group/components/MemberGroupSelect.vue' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - mobile: undefined, - password: undefined, - status: undefined, - nickname: undefined, - avatar: undefined, - name: undefined, - sex: undefined, - areaId: undefined, - birthday: undefined, - mark: undefined, - tagIds: [], - groupId: undefined -}) -const formRules = reactive({ - mobile: [{ required: true, message: '鎵嬫満鍙蜂笉鑳戒负绌�', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref -const areaList = ref([]) // 鍦板尯鍒楄〃 - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await UserApi.getUser(id) - } finally { - formLoading.value = false - } - } - // 鑾峰緱鍦板尯鍒楄〃 - areaList.value = await AreaApi.getAreaTree() -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as UserApi.UserVO - if (formType.value === 'create') { - // 璇存槑锛氱洰鍓嶆殏鏃舵病鏈夋柊澧炴搷浣溿�傚鏋滆嚜宸变笟鍔¢渶瑕侊紝鍙互杩涜鎵╁睍 - // await UserApi.createUser(data) - message.success(t('common.createSuccess')) - } else { - await UserApi.updateUser(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - mobile: undefined, - password: undefined, - status: undefined, - nickname: undefined, - avatar: undefined, - name: undefined, - sex: undefined, - areaId: undefined, - birthday: undefined, - mark: undefined, - tagIds: [], - groupId: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/user/UserLevelUpdateForm.vue b/src/views/member/user/UserLevelUpdateForm.vue deleted file mode 100644 index e583f4a..0000000 --- a/src/views/member/user/UserLevelUpdateForm.vue +++ /dev/null @@ -1,101 +0,0 @@ -<template> - <Dialog title="淇敼鐢ㄦ埛绛夌骇" v-model="dialogVisible" width="600"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="id"> - <el-input v-model="formData.id" placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" class="!w-240px" disabled /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鏄电О" prop="nickname"> - <el-input - v-model="formData.nickname" - placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" - class="!w-240px" - disabled - /> - </el-form-item> - <el-form-item label="鐢ㄦ埛绛夌骇" prop="levelId"> - <MemberLevelSelect v-model="formData.levelId" /> - </el-form-item> - <el-form-item label="淇敼鍘熷洜" prop="reason"> - <el-input type="textarea" v-model="formData.reason" placeholder="璇疯緭鍏ヤ慨鏀瑰師鍥�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as UserApi from '@/api/member/user' -import MemberLevelSelect from '@/views/member/level/components/MemberLevelSelect.vue' - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - nickname: undefined, - levelId: undefined, - reason: undefined -}) -const formRules = reactive({ - reason: [{ required: true, message: '淇敼鍘熷洜涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (id?: number) => { - dialogVisible.value = true - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await UserApi.getUser(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await UserApi.updateUserLevel(formData.value) - - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - nickname: undefined, - levelId: undefined, - reason: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/member/user/UserPointUpdateForm.vue b/src/views/member/user/UserPointUpdateForm.vue deleted file mode 100644 index 967ebe0..0000000 --- a/src/views/member/user/UserPointUpdateForm.vue +++ /dev/null @@ -1,128 +0,0 @@ -<template> - <Dialog title="淇敼鐢ㄦ埛绉垎" v-model="dialogVisible" width="600"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="id"> - <el-input v-model="formData.id" class="!w-240px" disabled /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鏄电О" prop="nickname"> - <el-input v-model="formData.nickname" class="!w-240px" disabled /> - </el-form-item> - <el-form-item label="鍙樺姩鍓嶇Н鍒�" prop="point"> - <el-input-number v-model="formData.point" class="!w-240px" disabled /> - </el-form-item> - <el-form-item label="鍙樺姩绫诲瀷" prop="changeType"> - <el-radio-group v-model="formData.changeType"> - <el-radio :label="1">澧炲姞</el-radio> - <el-radio :label="-1">鍑忓皯</el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鍙樺姩绉垎" prop="changePoint"> - <el-input-number v-model="formData.changePoint" class="!w-240px" :min="0" :precision="0" /> - </el-form-item> - <el-form-item label="鍙樺姩鍚庣Н鍒�"> - <el-input-number v-model="pointResult" class="!w-240px" disabled /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as UserApi from '@/api/member/user' - -/** 淇敼鐢ㄦ埛绉垎琛ㄥ崟 */ -defineOptions({ name: 'UpdatePointForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref({ - id: undefined, - nickname: undefined, - point: 0, - changePoint: 0, - changeType: 1 -}) -const formRules = reactive({ - changePoint: [{ required: true, message: '鍙樺姩绉垎涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (id?: number) => { - dialogVisible.value = true - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await UserApi.getUser(id) - formData.value.changeType = 1 // 榛樿澧炲姞绉垎 - formData.value.changePoint = 0 // 鍙樺姩绉垎榛樿0 - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - - if (formData.value.changePoint < 1) { - message.error('鍙樺姩绉垎涓嶈兘灏忎簬 1') - return - } - if (pointResult.value < 0) { - message.error('鍙樺姩鍚庣殑绉垎涓嶈兘灏忎簬 0') - return - } - - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await UserApi.updateUserPoint({ - id: formData.value.id, - point: formData.value.changePoint * formData.value.changeType - }) - - message.success(t('common.updateSuccess')) - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - nickname: undefined, - levelId: undefined, - reason: undefined - } - formRef.value?.resetFields() -} - -/** 鍙樺姩鍚庣殑绉垎 */ -const pointResult = computed( - () => formData.value.point + formData.value.changePoint * formData.value.changeType -) -</script> diff --git a/src/views/member/user/components/balance-list.vue b/src/views/member/user/components/balance-list.vue deleted file mode 100644 index 3e9d178..0000000 --- a/src/views/member/user/components/balance-list.vue +++ /dev/null @@ -1,14 +0,0 @@ -<script lang="ts"> -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'BalanceList' -}) -</script> - -<!-- TODO @鑺嬭壙锛氭湭鏉ュ疄鐜帮紝绛夊懆寤虹殑 --> -<template> - <div>浣欓鍒楄〃</div> -</template> - -<style scoped lang="scss"></style> diff --git a/src/views/member/user/detail/UserAccountInfo.vue b/src/views/member/user/detail/UserAccountInfo.vue deleted file mode 100644 index 56a6ab6..0000000 --- a/src/views/member/user/detail/UserAccountInfo.vue +++ /dev/null @@ -1,87 +0,0 @@ -<template> - <el-descriptions :column="2"> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 绛夌骇 " icon="svg-icon:member_level" /> - </template> - {{ user.levelName || '鏃�' }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 鎴愰暱鍊� " icon="ep:suitcase" /> - </template> - {{ user.experience || 0 }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 褰撳墠绉垎 " icon="ep:coin" /> - </template> - {{ user.point || 0 }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 鎬荤Н鍒� " icon="ep:coin" /> - </template> - {{ user.totalPoint || 0 }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 褰撳墠浣欓 " icon="svg-icon:member_balance" /> - </template> - {{ fenToYuan(wallet.balance || 0) }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 鏀嚭閲戦 " icon="svg-icon:member_expenditure_balance" /> - </template> - {{ fenToYuan(wallet.totalExpense || 0) }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label=" 鍏呭�奸噾棰� " icon="svg-icon:member_recharge_balance" /> - </template> - {{ fenToYuan(wallet.totalRecharge || 0) }} - </el-descriptions-item> - </el-descriptions> -</template> -<script setup lang="ts"> -import { DescriptionsItemLabel } from '@/components/Descriptions' -import * as UserApi from '@/api/member/user' -import * as WalletApi from '@/api/pay/wallet/balance' -import { UserTypeEnum } from '@/utils/constants' -import { fenToYuan } from '@/utils' - -const props = defineProps<{ user: UserApi.UserVO }>() // 鐢ㄦ埛淇℃伅 -const WALLET_INIT_DATA = { - balance: 0, - totalExpense: 0, - totalRecharge: 0 -} as WalletApi.WalletVO // 閽卞寘鍒濆鍖栨暟鎹� -const wallet = ref<WalletApi.WalletVO>(WALLET_INIT_DATA) // 閽卞寘淇℃伅 - -/** 鏌ヨ鐢ㄦ埛閽卞寘淇℃伅 */ -const getUserWallet = async () => { - if (!props.user.id) { - wallet.value = WALLET_INIT_DATA - return - } - const params = { userId: props.user.id } - wallet.value = (await WalletApi.getWallet(params)) || WALLET_INIT_DATA -} - -/** 鐩戝惉鐢ㄦ埛缂栧彿鍙樺寲 */ -watch( - () => props.user.id, - () => getUserWallet(), - { immediate: true } -) -</script> -<style scoped lang="scss"> -.cell-item { - display: inline; -} - -.cell-item::after { - content: ':'; -} -</style> diff --git a/src/views/member/user/detail/UserAddressList.vue b/src/views/member/user/detail/UserAddressList.vue deleted file mode 100644 index a37caba..0000000 --- a/src/views/member/user/detail/UserAddressList.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鍦板潃缂栧彿" align="center" prop="id" width="150px" /> - <el-table-column label="鏀朵欢浜哄悕绉�" align="center" prop="name" width="150px" /> - <el-table-column label="鎵嬫満鍙�" align="center" prop="mobile" width="150px" /> - <el-table-column label="鍦板尯缂栫爜" align="center" prop="areaId" width="150px" /> - <el-table-column label="鏀朵欢璇︾粏鍦板潃" align="center" prop="detailAddress" /> - <el-table-column label="鏄惁榛樿" align="center" prop="defaultStatus" width="150px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="Number(scope.row.defaultStatus)" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as AddressApi from '@/api/member/address' - -const { userId }: { userId: number } = defineProps({ - userId: { - type: Number, - required: true - } -}) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - list.value = await AddressApi.getAddressList({ userId }) - } finally { - loading.value = false - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> - -<style scoped lang="scss"></style> diff --git a/src/views/member/user/detail/UserBasicInfo.vue b/src/views/member/user/detail/UserBasicInfo.vue deleted file mode 100644 index 075450e..0000000 --- a/src/views/member/user/detail/UserBasicInfo.vue +++ /dev/null @@ -1,85 +0,0 @@ -<template> - <el-card shadow="never"> - <template #header> - <slot name="header"></slot> - </template> - <el-row> - <el-col :span="4"> - <ElAvatar shape="square" :size="140" :src="user.avatar || undefined" /> - </el-col> - <el-col :span="20"> - <el-descriptions :column="2"> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鐢ㄦ埛鍚�" icon="ep:user" /> - </template> - {{ user.name || '绌�' }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鏄电О" icon="ep:user" /> - </template> - {{ user.nickname }} - </el-descriptions-item> - <el-descriptions-item label="鎵嬫満鍙�"> - <template #label> - <descriptions-item-label label="鎵嬫満鍙�" icon="ep:phone" /> - </template> - {{ user.mobile }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鎬у埆" icon="fa:mars-double" /> - </template> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="user.sex" /> - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鎵�鍦ㄥ湴" icon="ep:location" /> - </template> - {{ user.areaName }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="娉ㄥ唽 IP" icon="ep:position" /> - </template> - {{ user.registerIp }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鐢熸棩" icon="fa:birthday-cake" /> - </template> - {{ user.birthday ? formatDate(user.birthday) : '绌�' }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="娉ㄥ唽鏃堕棿" icon="ep:calendar" /> - </template> - {{ user.createTime ? formatDate(user.createTime) : '绌�' }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <descriptions-item-label label="鏈�鍚庣櫥褰曟椂闂�" icon="ep:calendar" /> - </template> - {{ user.loginDate ? formatDate(user.loginDate) : '绌�' }} - </el-descriptions-item> - </el-descriptions> - </el-col> - </el-row> - </el-card> -</template> -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import * as UserApi from '@/api/member/user' -import { DescriptionsItemLabel } from '@/components/Descriptions/index' - -const { user } = defineProps<{ user: UserApi.UserVO }>() -</script> -<style scoped lang="scss"> -.card-header { - display: flex; - justify-content: space-between; - align-items: center; -} -</style> diff --git a/src/views/member/user/detail/UserBrokerageList.vue b/src/views/member/user/detail/UserBrokerageList.vue deleted file mode 100644 index db88787..0000000 --- a/src/views/member/user/detail/UserBrokerageList.vue +++ /dev/null @@ -1,125 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="85px" - > - <el-form-item label="鐢ㄦ埛绫诲瀷" prop="level"> - <el-radio-group v-model="queryParams.level" @change="handleQuery"> - <el-radio-button checked>鍏ㄩ儴</el-radio-button> - <el-radio-button label="1">涓�绾ф帹骞夸汉</el-radio-button> - <el-radio-button label="2">浜岀骇鎺ㄥ箍浜�</el-radio-button> - </el-radio-group> - </el-form-item> - <el-form-item label="缁戝畾鏃堕棿" prop="bindUserTime"> - <el-date-picker - v-model="queryParams.bindUserTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="id" min-width="80px" /> - <el-table-column label="澶村儚" align="center" prop="avatar" width="70px"> - <template #default="scope"> - <el-avatar :src="scope.row.avatar" /> - </template> - </el-table-column> - <el-table-column label="鏄电О" align="center" prop="nickname" min-width="80px" /> - <el-table-column label="绛夌骇" align="center" prop="level" min-width="80px"> - <template #default="scope"> - <el-tag v-if="scope.row.bindUserId === bindUserId">涓�绾�</el-tag> - <el-tag v-else>浜岀骇</el-tag> - </template> - </el-table-column> - <el-table-column - label="缁戝畾鏃堕棿" - align="center" - prop="bindUserTime" - :formatter="dateFormatter" - width="170px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as BrokerageUserApi from '@/api/mall/trade/brokerage/user' - -/** 鎺ㄥ箍浜哄垪琛� */ -defineOptions({ name: 'UserBrokerageList' }) - -const { bindUserId }: { bindUserId: number } = defineProps({ - bindUserId: { - type: Number, - required: true - } -}) //鐢ㄦ埛缂栧彿 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - bindUserId: null, - level: '', - bindUserTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - queryParams.bindUserId = bindUserId - const data = await BrokerageUserApi.getBrokerageUserPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/member/user/detail/UserCouponList.vue b/src/views/member/user/detail/UserCouponList.vue deleted file mode 100644 index 2279b8a..0000000 --- a/src/views/member/user/detail/UserCouponList.vue +++ /dev/null @@ -1,190 +0,0 @@ -<template> - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" />鎼滅储 </el-button> - <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" />閲嶇疆 </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <ContentWrap> - <!-- Tab 閫夐」锛氱湡姝g殑鍐呭鍦� Lab --> - <el-tabs v-model="activeTab" type="card" @tab-change="onTabChange"> - <el-tab-pane - v-for="tab in statusTabs" - :key="tab.value" - :label="tab.label" - :name="tab.value" - /> - </el-tabs> - - <!-- 鍒楄〃 --> - <el-table v-loading="loading" :data="list"> - <el-table-column label="浼樻儬鍔�" align="center" prop="name" /> - <el-table-column label="浼樻儬鍒哥被鍨�" align="center" prop="discountType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" /> - </template> - </el-table-column> - <el-table-column label="棰嗗彇鏂瑰紡" align="center" prop="takeType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" /> - </template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="棰嗗彇鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column - label="浣跨敤鏃堕棿" - align="center" - prop="useTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> - <template #default="scope"> - <el-button - v-hasPermi="['promotion:coupon:delete']" - type="danger" - link - @click="handleDelete(scope.row.id)" - > - 鍥炴敹 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts" name="UserCouponList"> -import { deleteCoupon, getCouponPage } from '@/api/mall/promotion/coupon/coupon' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' - -defineOptions({ name: 'UserCouponList' }) - -const { userId }: { userId: number } = defineProps({ - userId: { - type: Number, - required: true - } -}) //鐢ㄦ埛缂栧彿 - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 瀛楀吀琛ㄦ牸鏁版嵁 -// 鏌ヨ鍙傛暟 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - createTime: [], - status: undefined, - userIds: undefined -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -const activeTab = ref('all') // Tab 绛涢�� -const statusTabs = reactive([ - { - label: '鍏ㄩ儴', - value: 'all' - } -]) - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - // 鎵ц鏌ヨ - try { - queryParams.userIds = userId - const data = await getCouponPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 浜屾纭 - await message.confirm( - '鍥炴敹灏嗕細鏀跺洖浼氬憳棰嗗彇鐨勫緟浣跨敤鐨勪紭鎯犲埜锛屽凡浣跨敤鐨勫皢鏃犳硶鍥炴敹锛岀‘瀹氳鍥炴敹鎵�閫変紭鎯犲埜鍚楋紵' - ) - // 鍙戣捣鍒犻櫎 - await deleteCoupon(id) - message.notifySuccess('鍥炴敹鎴愬姛') - // 閲嶆柊鍔犺浇鍒楄〃 - await getList() - } catch {} -} - -/** tab 鍒囨崲 */ -const onTabChange = (tabName) => { - queryParams.status = tabName === 'all' ? undefined : tabName - getList() -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() - // 璁剧疆 statuses 杩囨护 - for (const dict of getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_STATUS)) { - statusTabs.push({ - label: dict.label, - value: dict.value as string - }) - } -}) -</script> diff --git a/src/views/member/user/detail/UserExperienceRecordList.vue b/src/views/member/user/detail/UserExperienceRecordList.vue deleted file mode 100644 index 64414ad..0000000 --- a/src/views/member/user/detail/UserExperienceRecordList.vue +++ /dev/null @@ -1,158 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="涓氬姟绫诲瀷" prop="bizType"> - <el-select - v-model="queryParams.bizType" - placeholder="璇烽�夋嫨涓氬姟绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_EXPERIENCE_BIZ_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鏍囬" prop="title"> - <el-input - v-model="queryParams.title" - placeholder="璇疯緭鍏ユ爣棰�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" width="150px" /> - <el-table-column - label="鑾峰緱鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - /> - <el-table-column label="缁忛獙" align="center" prop="experience" width="150px"> - <template #default="scope"> - <el-tag v-if="scope.row.experience > 0" class="ml-2" type="success" effect="dark"> - +{{ scope.row.experience }} - </el-tag> - <el-tag v-else class="ml-2" type="danger" effect="dark"> - {{ scope.row.experience }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鎬荤粡楠�" align="center" prop="totalExperience" width="150px"> - <template #default="scope"> - <el-tag class="ml-2" effect="dark"> - {{ scope.row.totalExperience }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鏍囬" align="center" prop="title" width="150px" /> - <el-table-column label="鎻忚堪" align="center" prop="description" /> - <el-table-column label="涓氬姟缂栧彿" align="center" prop="bizId" width="150px" /> - <el-table-column label="涓氬姟绫诲瀷" align="center" prop="bizType" width="150px"> - <!-- TODO 鑺嬭壙锛氭澶勫簲鍒涘缓瀵瑰簲鐨勫瓧鍏� --> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.MEMBER_EXPERIENCE_BIZ_TYPE" :value="scope.row.bizType" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as ExperienceRecordApi from '@/api/member/experience-record/index' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - -defineOptions({ name: 'UserExperienceRecordList' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: null, - bizId: null, - bizType: null, - title: null, - description: null, - experience: null, - totalExperience: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await ExperienceRecordApi.getExperienceRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -const { userId } = defineProps({ - userId: { - type: Number, - required: true - } -}) -/** 鍒濆鍖� **/ -onMounted(() => { - queryParams.userId = userId - getList() -}) -</script> diff --git a/src/views/member/user/detail/UserFavoriteList.vue b/src/views/member/user/detail/UserFavoriteList.vue deleted file mode 100644 index afab9a0..0000000 --- a/src/views/member/user/detail/UserFavoriteList.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column key="id" align="center" label="鍟嗗搧缂栧彿" width="180" prop="id" /> - <el-table-column label="鍟嗗搧鍥�" min-width="80"> - <template #default="{ row }"> - <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> - </template> - </el-table-column> - <el-table-column :show-overflow-tooltip="true" label="鍟嗗搧鍚嶇О" min-width="300" prop="name" /> - <el-table-column align="center" label="鍟嗗搧鍞环" min-width="90" prop="price"> - <template #default="{ row }"> {{ floatToFixed2(row.price) }}鍏�</template> - </el-table-column> - <el-table-column align="center" label="閿�閲�" min-width="90" prop="salesCount" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鏀惰棌鏃堕棿" - prop="createTime" - width="180" - /> - <el-table-column align="center" label="鐘舵��" min-width="80"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as FavoriteApi from '@/api/mall/product/favorite' -import { floatToFixed2 } from '@/utils' - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - createTime: [], - userId: NaN -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await FavoriteApi.getFavoritePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -const { userId } = defineProps({ - userId: { - type: Number, - required: true - } -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - queryParams.userId = userId - getList() -}) -</script> diff --git a/src/views/member/user/detail/UserOrderList.vue b/src/views/member/user/detail/UserOrderList.vue deleted file mode 100644 index bae0bf0..0000000 --- a/src/views/member/user/detail/UserOrderList.vue +++ /dev/null @@ -1,279 +0,0 @@ -<template> - <!-- 鎼滅储 --> - <ContentWrap> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="璁㈠崟鐘舵��" prop="status"> - <el-select v-model="queryParams.status" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鏀粯鏂瑰紡" prop="payChannelCode"> - <el-select - v-model="queryParams.payChannelCode" - class="!w-280px" - clearable - placeholder="鍏ㄩ儴" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-280px" - end-placeholder="鑷畾涔夋椂闂�" - start-placeholder="鑷畾涔夋椂闂�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="璁㈠崟鏉ユ簮" prop="terminal"> - <el-select v-model="queryParams.terminal" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="璁㈠崟绫诲瀷" prop="type"> - <el-select v-model="queryParams.type" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="閰嶉�佹柟寮�" prop="deliveryType"> - <el-select v-model="queryParams.deliveryType" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type" - label="蹇�掑叕鍙�" - prop="logisticsId" - > - <el-select v-model="queryParams.logisticsId" class="!w-280px" clearable placeholder="鍏ㄩ儴"> - <el-option - v-for="item in deliveryExpressList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" - label="鑷彁闂ㄥ簵" - prop="pickUpStoreId" - > - <el-select - v-model="queryParams.pickUpStoreId" - class="!w-280px" - clearable - multiple - placeholder="鍏ㄩ儴" - > - <el-option - v-for="item in pickUpStoreList" - :key="item.id" - :label="item.name" - :value="item.id" - /> - </el-select> - </el-form-item> - <el-form-item - v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type" - label="鏍搁攢鐮�" - prop="pickUpVerifyCode" - > - <el-input - v-model="queryParams.pickUpVerifyCode" - class="!w-280px" - clearable - placeholder="璇疯緭鍏ヨ嚜鎻愭牳閿�鐮�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鑱氬悎鎼滅储"> - <el-input - v-show="true" - v-model="queryParams[queryType.queryParam]" - class="!w-280px" - clearable - placeholder="璇疯緭鍏�" - > - <template #prepend> - <el-select - v-model="queryType.queryParam" - class="!w-110px" - clearable - placeholder="鍏ㄩ儴" - @change="inputChangeSelect" - > - <el-option - v-for="dict in dynamicSearchList" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </template> - </el-input> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <!-- 娣诲姞 row-key="id" 瑙e喅鍒楁暟鎹腑鐨� table#header 鏁版嵁涓嶅埛鏂扮殑闂 --> - <el-table v-loading="loading" :data="list" row-key="id"> - <OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList"> - <template #default="{ row }"> - <el-button link type="primary" @click="openDetail(row.id)"> - <Icon icon="ep:notification" /> - 璇︽儏 - </el-button> - </template> - </OrderTableColumn> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> -</template> -<script lang="ts" setup> -import * as OrderApi from '@/api/mall/trade/order/index' -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' -import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' -import { FormInstance } from 'element-plus' -import { OrderTableColumn } from '@/views/mall/trade/order/components' -import { DeliveryTypeEnum } from '@/utils/constants' - -const { push } = useRouter() // 璺敱璺宠浆 - -const { userId } = defineProps<{ - userId: number -}>() - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 鑷彁闂ㄥ簵绮剧畝鍒楄〃 -const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 鐗╂祦鍏徃 -const queryFormRef = ref<FormInstance>() // 鎼滅储鐨勮〃鍗� -// 琛ㄥ崟鎼滅储 -const queryParams = ref({ - pageNo: 1, // 椤垫暟 - pageSize: 10, // 姣忛〉鏄剧ず鏁伴噺 - userId: userId, - status: undefined, // 璁㈠崟鐘舵�� - payChannelCode: undefined, // 鏀粯鏂瑰紡 - createTime: undefined, // 鍒涘缓鏃堕棿 - terminal: undefined, // 璁㈠崟鏉ユ簮 - type: undefined, // 璁㈠崟绫诲瀷 - deliveryType: undefined, // 閰嶉�佹柟寮� - logisticsId: undefined, // 蹇�掑叕鍙� - pickUpStoreId: undefined, // 鑷彁闂ㄥ簵 - pickUpVerifyCode: undefined // 鑷彁鏍搁攢鐮� -}) -const queryType = reactive({ queryParam: '' }) // 璁㈠崟鎼滅储绫诲瀷 queryParam - -// 璁㈠崟鑱氬悎鎼滅储 select 绫诲瀷閰嶇疆锛堝姩鎬佹悳绱級 -const dynamicSearchList = ref([ - { value: 'no', label: '璁㈠崟鍙�' }, - { value: 'userNickname', label: '鐢ㄦ埛鏄电О' }, - { value: 'userMobile', label: '鐢ㄦ埛鐢佃瘽' } -]) -/** - * 鑱氬悎鎼滅储鍒囨崲鏌ヨ瀵硅薄鏃惰Е鍙� - * @param val - */ -const inputChangeSelect = (val: string) => { - dynamicSearchList.value - .filter((item) => item.value !== val) - ?.forEach((item1) => { - // 娓呴櫎闆嗗悎鎼滅储鏃犵敤灞炴�� - if (queryParams.value.hasOwnProperty(item1.value)) { - delete queryParams.value[item1.value] - } - }) -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = async () => { - queryParams.value.pageNo = 1 - await getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - queryParams.value.userId = userId - handleQuery() -} -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await OrderApi.getOrderPage(queryParams.value) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鏌ョ湅璁㈠崟璇︽儏 */ -const openDetail = (id: number) => { - push({ name: 'TradeOrderDetail', params: { id } }) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - pickUpStoreList.value = await PickUpStoreApi.getListAllSimple() - deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() -}) -</script> diff --git a/src/views/member/user/detail/UserPointList.vue b/src/views/member/user/detail/UserPointList.vue deleted file mode 100644 index 9754b29..0000000 --- a/src/views/member/user/detail/UserPointList.vue +++ /dev/null @@ -1,152 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="涓氬姟绫诲瀷" prop="bizType"> - <el-select - v-model="queryParams.bizType" - placeholder="璇烽�夋嫨涓氬姟绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_POINT_BIZ_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="绉垎鏍囬" prop="title"> - <el-input - v-model="queryParams.title" - placeholder="璇疯緭鍏ョН鍒嗘爣棰�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鑾峰緱鏃堕棿" prop="createDate"> - <el-date-picker - v-model="queryParams.createDate" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 閲嶇疆 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" width="180" /> - <el-table-column - label="鑾峰緱鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180" - /> - <el-table-column label="鑾峰緱绉垎" align="center" prop="point" width="100"> - <template #default="scope"> - <el-tag v-if="scope.row.point > 0" class="ml-2" type="success" effect="dark"> - +{{ scope.row.point }} - </el-tag> - <el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag> - </template> - </el-table-column> - <el-table-column label="鎬荤Н鍒�" align="center" prop="totalPoint" width="100" /> - <el-table-column label="鏍囬" align="center" prop="title" /> - <el-table-column label="鎻忚堪" align="center" prop="description" /> - <el-table-column label="涓氬姟缂栫爜" align="center" prop="bizId" /> - <el-table-column label="涓氬姟绫诲瀷" align="center" prop="bizType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.MEMBER_POINT_BIZ_TYPE" :value="scope.row.bizType" /> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as RecordApi from '@/api//member/point/record' - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - bizType: undefined, - title: null, - createDate: [], - userId: NaN -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await RecordApi.getRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -const { userId } = defineProps({ - userId: { - type: Number, - required: true - } -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - queryParams.userId = userId - getList() -}) -</script> diff --git a/src/views/member/user/detail/UserSignList.vue b/src/views/member/user/detail/UserSignList.vue deleted file mode 100644 index c897274..0000000 --- a/src/views/member/user/detail/UserSignList.vue +++ /dev/null @@ -1,135 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="绛惧埌鐢ㄦ埛" prop="nickname"> - <el-input - v-model="queryParams.nickname" - placeholder="璇疯緭鍏ョ鍒扮敤鎴�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绛惧埌澶╂暟" prop="day"> - <el-input - v-model="queryParams.day" - placeholder="璇疯緭鍏ョ鍒板ぉ鏁�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绛惧埌鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column - label="绛惧埌澶╂暟" - align="center" - prop="day" - :formatter="(_, __, cellValue) => ['绗�', cellValue, '澶�'].join(' ')" - /> - <el-table-column label="鑾峰緱绉垎" align="center" prop="point" width="100"> - <template #default="scope"> - <el-tag v-if="scope.row.point > 0" class="ml-2" type="success" effect="dark"> - +{{ scope.row.point }} - </el-tag> - <el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag> - </template> - </el-table-column> - <el-table-column - label="绛惧埌鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as SignInRecordApi from '@/api/member/signin/record' - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: NaN, - nickname: null, - day: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await SignInRecordApi.getSignInRecordPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -const { userId } = defineProps({ - userId: { - type: Number, - required: true - } -}) - -/** 鍒濆鍖� **/ -onMounted(() => { - queryParams.userId = userId - getList() -}) -</script> diff --git a/src/views/member/user/detail/index.vue b/src/views/member/user/detail/index.vue deleted file mode 100644 index 6237cca..0000000 --- a/src/views/member/user/detail/index.vue +++ /dev/null @@ -1,135 +0,0 @@ -<template> - <div v-loading="loading"> - <el-row :gutter="10"> - <!-- 宸︿笂瑙掞細鍩烘湰淇℃伅 --> - <el-col :span="14" class="detail-info-item"> - <UserBasicInfo :user="user"> - <template #header> - <div class="card-header"> - <CardTitle title="鍩烘湰淇℃伅" /> - <el-button type="primary" size="small" text @click="openForm('update')"> - 缂栬緫 - </el-button> - </div> - </template> - </UserBasicInfo> - </el-col> - <!-- 鍙充笂瑙掞細璐︽埛淇℃伅 --> - <el-col :span="10" class="detail-info-item"> - <el-card shadow="never" class="h-full"> - <template #header> - <CardTitle title="璐︽埛淇℃伅" /> - </template> - <UserAccountInfo :user="user" /> - </el-card> - </el-col> - <!-- 涓嬭竟锛氳处鎴锋槑缁� --> - <!-- TODO 鑺嬭壙锛氥�愯鍗曠鐞嗐�戙�愬敭鍚庣鐞嗐�戙�愭敹钘忚褰曘��--> - <el-card header="璐︽埛鏄庣粏" style="width: 100%; margin-top: 20px" shadow="never"> - <template #header> - <CardTitle title="璐︽埛鏄庣粏" /> - </template> - <el-tabs> - <el-tab-pane label="绉垎"> - <UserPointList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="绛惧埌" lazy> - <UserSignList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="鎴愰暱鍊�" lazy> - <UserExperienceRecordList :user-id="id" /> - </el-tab-pane> - <!-- TODO @jason锛氬鍔犱竴涓綑棰濆彉鍖栵紱 --> - <el-tab-pane label="浣欓" lazy>浣欓(WIP)</el-tab-pane> - <el-tab-pane label="鏀惰揣鍦板潃" lazy> - <UserAddressList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="璁㈠崟绠$悊" lazy> - <UserOrderList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="鍞悗绠$悊" lazy>鍞悗绠$悊(WIP)</el-tab-pane> - <el-tab-pane label="鏀惰棌璁板綍" lazy> - <UserFavoriteList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="浼樻儬鍔�" lazy> - <UserCouponList :user-id="id" /> - </el-tab-pane> - <el-tab-pane label="鎺ㄥ箍鐢ㄦ埛" lazy> - <UserBrokerageList :bind-user-id="id" /> - </el-tab-pane> - </el-tabs> - </el-card> - </el-row> - </div> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <UserForm ref="formRef" @success="getUserData(id)" /> -</template> -<script setup lang="ts"> -import * as UserApi from '@/api/member/user' -import { useTagsViewStore } from '@/store/modules/tagsView' -import UserForm from '@/views/member/user/UserForm.vue' -import UserAccountInfo from './UserAccountInfo.vue' -import UserAddressList from './UserAddressList.vue' -import UserBasicInfo from './UserBasicInfo.vue' -import UserBrokerageList from './UserBrokerageList.vue' -import UserCouponList from './UserCouponList.vue' -import UserExperienceRecordList from './UserExperienceRecordList.vue' -import UserOrderList from './UserOrderList.vue' -import UserPointList from './UserPointList.vue' -import UserSignList from './UserSignList.vue' -import UserFavoriteList from './UserFavoriteList.vue' -import { CardTitle } from '@/components/Card/index' -import { ElMessage } from 'element-plus' - -defineOptions({ name: 'MemberDetail' }) - -const loading = ref(true) // 鍔犺浇涓� -const user = ref<UserApi.UserVO>({} as UserApi.UserVO) - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string) => { - formRef.value.open(type, id) -} - -/** 鑾峰緱鐢ㄦ埛 */ -const getUserData = async (id: number) => { - loading.value = true - try { - user.value = await UserApi.getUser(id) - } finally { - loading.value = false - } -} - -/** 鍒濆鍖� */ -const { currentRoute } = useRouter() // 璺敱 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 -const route = useRoute() -const id = Number(route.params.id) -onMounted(() => { - if (!id) { - ElMessage.warning('鍙傛暟閿欒锛屼細鍛樼紪鍙蜂笉鑳戒负绌猴紒') - delView(unref(currentRoute)) - return - } - getUserData(id) -}) -</script> -<style scoped lang="css"> -.detail-info-item:first-child { - padding-left: 0 !important; -} - -/* first-child 涓嶇敓鏁堟湁娌℃湁澶т浆缁欑湅涓媞.q */ -.detail-info-item:nth-child(2) { - padding-right: 0 !important; -} - -.card-header { - display: flex; - justify-content: space-between; - align-items: center; -} -</style> diff --git a/src/views/member/user/index.vue b/src/views/member/user/index.vue deleted file mode 100644 index 69bf6de..0000000 --- a/src/views/member/user/index.vue +++ /dev/null @@ -1,313 +0,0 @@ -<template> - <doc-alert title="浼氬憳鐢ㄦ埛銆佹爣绛俱�佸垎缁�" url="https://doc.iocoder.cn/member/user/" /> - - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛鏄电О" prop="nickname"> - <el-input - v-model="queryParams.nickname" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="鎵嬫満鍙�" prop="mobile"> - <el-input - v-model="queryParams.mobile" - class="!w-240px" - clearable - placeholder="璇疯緭鍏ユ墜鏈哄彿" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="娉ㄥ唽鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="鐧诲綍鏃堕棿" prop="loginDate"> - <el-date-picker - v-model="queryParams.loginDate" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="缁撴潫鏃ユ湡" - start-placeholder="寮�濮嬫棩鏈�" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鏍囩" prop="tagIds"> - <MemberTagSelect v-model="queryParams.tagIds" /> - </el-form-item> - <el-form-item label="鐢ㄦ埛绛夌骇" prop="levelId"> - <MemberLevelSelect v-model="queryParams.levelId" /> - </el-form-item> - <el-form-item label="鐢ㄦ埛鍒嗙粍" prop="groupId"> - <MemberGroupSelect v-model="queryParams.groupId" /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 閲嶇疆 - </el-button> - <el-button v-hasPermi="['promotion:coupon:send']" @click="openCoupon">鍙戦�佷紭鎯犲埜</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - @selection-change="handleSelectionChange" - > - <el-table-column type="selection" width="55" /> - <el-table-column align="center" label="鐢ㄦ埛缂栧彿" prop="id" width="120px" /> - <el-table-column align="center" label="澶村儚" prop="avatar" width="80px"> - <template #default="scope"> - <img :src="scope.row.avatar" style="width: 40px" /> - </template> - </el-table-column> - <el-table-column align="center" label="鎵嬫満鍙�" prop="mobile" width="120px" /> - <el-table-column align="center" label="鏄电О" prop="nickname" width="80px" /> - <el-table-column align="center" label="绛夌骇" prop="levelName" width="100px" /> - <el-table-column align="center" label="鍒嗙粍" prop="groupName" width="100px" /> - <el-table-column - :show-overflow-tooltip="false" - align="center" - label="鐢ㄦ埛鏍囩" - prop="tagNames" - > - <template #default="scope"> - <el-tag v-for="(tagName, index) in scope.row.tagNames" :key="index" class="mr-5px"> - {{ tagName }} - </el-tag> - </template> - </el-table-column> - <el-table-column align="center" label="绉垎" prop="point" width="100px" /> - <el-table-column align="center" label="鐘舵��" prop="status" width="100px"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="鐧诲綍鏃堕棿" - prop="loginDate" - width="180px" - /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="娉ㄥ唽鏃堕棿" - prop="createTime" - width="180px" - /> - <el-table-column - :show-overflow-tooltip="false" - align="center" - fixed="right" - label="鎿嶄綔" - width="100px" - > - <template #default="scope"> - <div class="flex items-center justify-center"> - <el-button link type="primary" @click="openDetail(scope.row.id)">璇︽儏</el-button> - <el-dropdown - v-hasPermi="[ - 'member:user:update', - 'member:user:update-level', - 'member:user:update-point', - 'member:user:update-balance' - ]" - @command="(command) => handleCommand(command, scope.row)" - > - <el-button link type="primary"> - <Icon icon="ep:d-arrow-right" /> - 鏇村 - </el-button> - <template #dropdown> - <el-dropdown-menu> - <el-dropdown-item - v-if="checkPermi(['member:user:update'])" - command="handleUpdate" - > - 缂栬緫 - </el-dropdown-item> - <el-dropdown-item - v-if="checkPermi(['member:user:update-level'])" - command="handleUpdateLevel" - > - 淇敼绛夌骇 - </el-dropdown-item> - <el-dropdown-item - v-if="checkPermi(['member:user:update-point'])" - command="handleUpdatePoint" - > - 淇敼绉垎 - </el-dropdown-item> - <el-dropdown-item - v-if="checkPermi(['member:user:update-balance'])" - command="handleUpdateBlance" - > - 淇敼浣欓(WIP) - </el-dropdown-item> - </el-dropdown-menu> - </template> - </el-dropdown> - </div> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <UserForm ref="formRef" @success="getList" /> - <!-- 淇敼鐢ㄦ埛绛夌骇寮圭獥 --> - <UserLevelUpdateForm ref="updateLevelFormRef" @success="getList" /> - <!-- 淇敼鐢ㄦ埛绉垎寮圭獥 --> - <UserPointUpdateForm ref="updatePointFormRef" @success="getList" /> - <!-- 鍙戦�佷紭鎯犲埜寮圭獥 --> - <CouponSendForm ref="couponSendFormRef" /> -</template> -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as UserApi from '@/api/member/user' -import { DICT_TYPE } from '@/utils/dict' -import UserForm from './UserForm.vue' -import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue' -import MemberLevelSelect from '@/views/member/level/components/MemberLevelSelect.vue' -import MemberGroupSelect from '@/views/member/group/components/MemberGroupSelect.vue' -import UserLevelUpdateForm from './UserLevelUpdateForm.vue' -import UserPointUpdateForm from './UserPointUpdateForm.vue' -import { CouponSendForm } from '@/views/mall/promotion/coupon/components' -import { checkPermi } from '@/utils/permission' - -defineOptions({ name: 'MemberUser' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - nickname: null, - mobile: null, - loginDate: [], - createTime: [], - tagIds: [], - levelId: null, - groupId: null -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const updateLevelFormRef = ref() // 淇敼浼氬憳绛夌骇琛ㄥ崟 -const updatePointFormRef = ref() // 淇敼浼氬憳绉垎琛ㄥ崟 -const selectedIds = ref<number[]>([]) // 琛ㄦ牸鐨勯�変腑 ID 鏁扮粍 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await UserApi.getUserPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鎵撳紑浼氬憳璇︽儏 */ -const { push } = useRouter() -const openDetail = (id: number) => { - push({ name: 'MemberUserDetail', params: { id } }) -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 琛ㄦ牸閫変腑浜嬩欢 */ -const handleSelectionChange = (rows: UserApi.UserVO[]) => { - selectedIds.value = rows.map((row) => row.id) -} - -/** 鍙戦�佷紭鎯犲埜 */ -const couponSendFormRef = ref() -const openCoupon = () => { - if (selectedIds.value.length === 0) { - message.warning('璇烽�夋嫨瑕佸彂閫佷紭鎯犲埜鐨勭敤鎴�') - return - } - couponSendFormRef.value.open(selectedIds.value) -} - -/** 鎿嶄綔鍒嗗彂 */ -const handleCommand = (command: string, row: UserApi.UserVO) => { - switch (command) { - case 'handleUpdate': - openForm('update', row.id) - break - case 'handleUpdateLevel': - updateLevelFormRef.value.open(row.id) - break - case 'handleUpdatePoint': - updatePointFormRef.value.open(row.id) - break - case 'handleUpdateBlance': - // todo @jason锛氬鍔犱竴涓�愪慨鏀逛綑棰濄�� - break - default: - break - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/pay/app/components/AppForm.vue b/src/views/pay/app/components/AppForm.vue deleted file mode 100644 index b99766c..0000000 --- a/src/views/pay/app/components/AppForm.vue +++ /dev/null @@ -1,130 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="160px" - > - <el-form-item label="搴旂敤鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ簲鐢ㄥ悕" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="鏀粯缁撴灉鐨勫洖璋冨湴鍧�" prop="orderNotifyUrl"> - <el-input v-model="formData.orderNotifyUrl" placeholder="璇疯緭鍏ユ敮浠樼粨鏋滅殑鍥炶皟鍦板潃" /> - </el-form-item> - <el-form-item label="閫�娆剧粨鏋滅殑鍥炶皟鍦板潃" prop="refundNotifyUrl"> - <el-input v-model="formData.refundNotifyUrl" placeholder="璇疯緭鍏ラ��娆剧粨鏋滅殑鍥炶皟鍦板潃" /> - </el-form-item> - <el-form-item label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as AppApi from '@/api/pay/app' -import { CommonStatusEnum } from '@/utils/constants' - -defineOptions({ name: 'PayAppForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - packageId: undefined, - contactName: undefined, - contactMobile: undefined, - accountCount: undefined, - expireTime: undefined, - domain: undefined, - status: CommonStatusEnum.ENABLE -}) -const formRules = reactive({ - name: [{ required: true, message: '搴旂敤鍚嶄笉鑳戒负绌�', trigger: 'blur' }], - status: [{ required: true, message: '寮�鍚姸鎬佷笉鑳戒负绌�', trigger: 'blur' }], - orderNotifyUrl: [{ required: true, message: '鏀粯缁撴灉鐨勫洖璋冨湴鍧�涓嶈兘涓虹┖', trigger: 'blur' }], - refundNotifyUrl: [{ required: true, message: '閫�娆剧粨鏋滅殑鍥炶皟鍦板潃涓嶈兘涓虹┖', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await AppApi.getApp(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = formData.value as unknown as AppApi.AppVO - if (formType.value === 'create') { - await AppApi.createApp(data) - message.success(t('common.createSuccess')) - } else { - await AppApi.updateApp(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - status: CommonStatusEnum.ENABLE, - remark: undefined, - orderNotifyUrl: undefined, - refundNotifyUrl: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/pay/app/components/channel/AlipayChannelForm.vue b/src/views/pay/app/components/channel/AlipayChannelForm.vue deleted file mode 100644 index 169ef8e..0000000 --- a/src/views/pay/app/components/channel/AlipayChannelForm.vue +++ /dev/null @@ -1,326 +0,0 @@ -<template> - <div> - <Dialog v-model="dialogVisible" :title="dialogTitle" @closed="close" width="830px"> - <el-form - ref="formRef" - :model="formData" - :formRules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label-width="180px" label="娓犻亾璐圭巼" prop="feeRate"> - <el-input v-model="formData.feeRate" placeholder="璇疯緭鍏ユ笭閬撹垂鐜�" clearable> - <template #append>%</template> - </el-input> - </el-form-item> - <el-form-item label-width="180px" label="寮�鏀惧钩鍙� APPID" prop="config.appId"> - <el-input v-model="formData.config.appId" placeholder="璇疯緭鍏ュ紑鏀惧钩鍙� APPID" clearable /> - </el-form-item> - <el-form-item label-width="180px" label="娓犻亾鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="parseInt(dict.value)" - :label="parseInt(dict.value)" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="缃戝叧鍦板潃" prop="config.serverUrl"> - <el-radio-group v-model="formData.config.serverUrl"> - <el-radio label="https://openapi.alipay.com/gateway.do">绾夸笂鐜</el-radio> - <el-radio label="https://openapi-sandbox.dl.alipaydev.com/gateway.do"> - 娌欑鐜 - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="绠楁硶绫诲瀷" prop="config.signType"> - <el-radio-group v-model="formData.config.signType"> - <el-radio key="RSA2" label="RSA2">RSA2</el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="鍏挜绫诲瀷" prop="config.mode"> - <el-radio-group v-model="formData.config.mode"> - <el-radio key="鍏挜妯″紡" :label="1">鍏挜妯″紡</el-radio> - <el-radio key="璇佷功妯″紡" :label="2">璇佷功妯″紡</el-radio> - </el-radio-group> - </el-form-item> - <div v-if="formData.config.mode === 1"> - <el-form-item label-width="180px" label="搴旂敤绉侀挜" prop="config.privateKey"> - <el-input - type="textarea" - :autosize="{ minRows: 8, maxRows: 8 }" - v-model="formData.config.privateKey" - placeholder="璇疯緭鍏ュ簲鐢ㄧ閽�" - clearable - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label="鏀粯瀹濆叕閽�" prop="config.alipayPublicKey"> - <el-input - type="textarea" - :autosize="{ minRows: 8, maxRows: 8 }" - v-model="formData.config.alipayPublicKey" - placeholder="璇疯緭鍏ユ敮浠樺疂鍏挜" - clearable - :style="{ width: '100%' }" - /> - </el-form-item> - </div> - <div v-if="formData.config.mode === 2"> - <el-form-item label-width="180px" label="搴旂敤绉侀挜" prop="config.privateKey"> - <el-input - type="textarea" - :autosize="{ minRows: 8, maxRows: 8 }" - v-model="formData.config.privateKey" - placeholder="璇疯緭鍏ュ簲鐢ㄧ閽�" - clearable - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label="鍟嗘埛鍏挜搴旂敤璇佷功" prop="config.appCertContent"> - <el-input - v-model="formData.config.appCertContent" - type="textarea" - placeholder="璇蜂笂浼犲晢鎴峰叕閽ュ簲鐢ㄨ瘉涔�" - readonly - :autosize="{ minRows: 8, maxRows: 8 }" - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label=""> - <el-upload - action="" - ref="privateKeyContentFile" - :limit="1" - :accept="fileAccept" - :http-request="appCertUpload" - :before-upload="fileBeforeUpload" - > - <el-button type="primary"> - <Icon icon="ep:upload" class="mr-5px" /> 鐐瑰嚮涓婁紶 - </el-button> - </el-upload> - </el-form-item> - <el-form-item - label-width="180px" - label="鏀粯瀹濆叕閽ヨ瘉涔�" - prop="config.alipayPublicCertContent" - > - <el-input - v-model="formData.config.alipayPublicCertContent" - type="textarea" - placeholder="璇蜂笂浼犳敮浠樺疂鍏挜璇佷功" - readonly - :autosize="{ minRows: 8, maxRows: 8 }" - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label=""> - <el-upload - ref="privateCertContentFile" - action="" - :limit="1" - :accept="fileAccept" - :before-upload="fileBeforeUpload" - :http-request="alipayPublicCertUpload" - > - <el-button type="primary"> - <Icon icon="ep:upload" class="mr-5px" /> 鐐瑰嚮涓婁紶 - </el-button> - </el-upload> - </el-form-item> - <el-form-item label-width="180px" label="鏍硅瘉涔�" prop="config.rootCertContent"> - <el-input - v-model="formData.config.rootCertContent" - type="textarea" - placeholder="璇蜂笂浼犳牴璇佷功" - readonly - :autosize="{ minRows: 8, maxRows: 8 }" - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label=""> - <el-upload - ref="privateCertContentFile" - :limit="1" - :accept="fileAccept" - action="" - :before-upload="fileBeforeUpload" - :http-request="rootCertUpload" - > - <el-button type="primary"> - <Icon icon="ep:upload" class="mr-5px" /> 鐐瑰嚮涓婁紶 - </el-button> - </el-upload> - </el-form-item> - </div> - <el-form-item label-width="180px" label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" :style="{ width: '100%' }" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - </div> -</template> -<script lang="ts" setup> -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getDictOptions } from '@/utils/dict' -import * as ChannelApi from '@/api/pay/channel' - -defineOptions({ name: 'AlipayChannelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<any>({ - appId: '', - code: '', - status: undefined, - feeRate: undefined, - remark: '', - config: { - appId: '', - serverUrl: null, - signType: '', - mode: null, - privateKey: '', - alipayPublicKey: '', - appCertContent: '', - alipayPublicCertContent: '', - rootCertContent: '' - } -}) -const formRules = { - feeRate: [{ required: true, message: '璇疯緭鍏ユ笭閬撹垂鐜�', trigger: 'blur' }], - status: [{ required: true, message: '娓犻亾鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - 'config.appId': [{ required: true, message: '璇疯緭鍏ュ紑鏀惧钩鍙颁笂鍒涘缓鐨勫簲鐢ㄧ殑 ID', trigger: 'blur' }], - 'config.serverUrl': [{ required: true, message: '璇蜂紶鍏ョ綉鍏冲湴鍧�', trigger: 'blur' }], - 'config.signType': [{ required: true, message: '璇蜂紶鍏ョ鍚嶇畻娉曠被鍨�', trigger: 'blur' }], - 'config.mode': [{ required: true, message: '鍏挜绫诲瀷涓嶈兘涓虹┖', trigger: 'blur' }], - 'config.privateKey': [{ required: true, message: '璇疯緭鍏ュ晢鎴风閽�', trigger: 'blur' }], - 'config.alipayPublicKey': [ - { required: true, message: '璇疯緭鍏ユ敮浠樺疂鍏挜瀛楃涓�', trigger: 'blur' } - ], - 'config.appCertContent': [{ required: true, message: '璇蜂笂浼犲晢鎴峰叕閽ュ簲鐢ㄨ瘉涔�', trigger: 'blur' }], - 'config.alipayPublicCertContent': [ - { required: true, message: '璇蜂笂浼犳敮浠樺疂鍏挜璇佷功', trigger: 'blur' } - ], - 'config.rootCertContent': [{ required: true, message: '璇蜂笂浼犳寚瀹氭牴璇佷功', trigger: 'blur' }] -} -const fileAccept = '.crt' -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (appId, code) => { - dialogVisible.value = true - formLoading.value = true - resetForm(appId, code) - // 鍔犺浇鏁版嵁 - try { - const data = await ChannelApi.getChannel(appId, code) - if (data && data.id) { - formData.value = data - formData.value.config = JSON.parse(data.config) - } - dialogTitle.value = !formData.value.id ? '鍒涘缓鏀粯娓犻亾' : '缂栬緫鏀粯娓犻亾' - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } as unknown as ChannelApi.ChannelVO - data.config = JSON.stringify(formData.value.config) - if (!data.id) { - await ChannelApi.createChannel(data) - message.success(t('common.createSuccess')) - } else { - await ChannelApi.updateChannel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = (appId, code) => { - formData.value = { - appId: appId, - code: code, - status: CommonStatusEnum.ENABLE, - remark: '', - feeRate: null, - config: { - appId: '', - serverUrl: null, - signType: 'RSA2', - mode: null, - privateKey: '', - alipayPublicKey: '', - appCertContent: '', - alipayPublicCertContent: '', - rootCertContent: '' - } - } - formRef.value?.resetFields() -} - -const fileBeforeUpload = (file) => { - let format = '.' + file.name.split('.')[1] - if (format !== fileAccept) { - message.error(`璇蜂笂浼犳寚瀹氭牸寮�"${fileAccept}"鏂囦欢`) - return false - } - let isRightSize = file.size / 1024 / 1024 < 2 - if (!isRightSize) { - message.error('鏂囦欢澶у皬瓒呰繃 2MB') - } - return isRightSize -} - -const appCertUpload = (event) => { - const readFile = new FileReader() - readFile.onload = (e: any) => { - formData.value.config.appCertContent = e.target.result - } - readFile.readAsText(event.file) -} - -const alipayPublicCertUpload = (event) => { - const readFile = new FileReader() - readFile.onload = (e: any) => { - formData.value.config.alipayPublicCertContent = e.target.result - } - readFile.readAsText(event.file) -} - -const rootCertUpload = (event) => { - const readFile = new FileReader() - readFile.onload = (e: any) => { - formData.value.config.rootCertContent = e.target.result - } - readFile.readAsText(event.file) -} -</script> diff --git a/src/views/pay/app/components/channel/MockChannelForm.vue b/src/views/pay/app/components/channel/MockChannelForm.vue deleted file mode 100644 index 49cb3ab..0000000 --- a/src/views/pay/app/components/channel/MockChannelForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <div> - <Dialog v-model="dialogVisible" :title="dialogTitle" @closed="close" width="800px"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label-width="180px" label="娓犻亾鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="parseInt(dict.value)" - :label="parseInt(dict.value)" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" :style="{ width: '100%' }" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - </div> -</template> -<script lang="ts" setup> -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getDictOptions } from '@/utils/dict' -import * as ChannelApi from '@/api/pay/channel' - -defineOptions({ name: 'MockChannelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<any>({ - appId: '', - code: '', - status: undefined, - feeRate: 0, - remark: '', - config: { - name: 'mock-conf' - } -}) -const formRules = { - status: [{ required: true, message: '娓犻亾鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -} -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (appId, code) => { - dialogVisible.value = true - formLoading.value = true - resetForm(appId, code) - // 鍔犺浇鏁版嵁 - try { - const data = await ChannelApi.getChannel(appId, code) - - if (data && data.id) { - formData.value = data - formData.value.config = JSON.parse(data.config) - } - dialogTitle.value = !formData.value.id ? '鍒涘缓鏀粯娓犻亾' : '缂栬緫鏀粯娓犻亾' - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } as unknown as ChannelApi.ChannelVO - data.config = JSON.stringify(formData.value.config) - if (!data.id) { - await ChannelApi.createChannel(data) - message.success(t('common.createSuccess')) - } else { - await ChannelApi.updateChannel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = (appId, code) => { - formData.value = { - appId: appId, - code: code, - status: CommonStatusEnum.ENABLE, - remark: '', - feeRate: 0, - config: { - name: 'mock-conf' - } - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/pay/app/components/channel/WalletChannelForm.vue b/src/views/pay/app/components/channel/WalletChannelForm.vue deleted file mode 100644 index cbdb542..0000000 --- a/src/views/pay/app/components/channel/WalletChannelForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <div> - <Dialog v-model="dialogVisible" :title="dialogTitle" @closed="close" width="800px"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label-width="180px" label="娓犻亾鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="parseInt(dict.value)" - :label="parseInt(dict.value)" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" :style="{ width: '100%' }" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - </div> -</template> -<script lang="ts" setup> -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getDictOptions } from '@/utils/dict' -import * as ChannelApi from '@/api/pay/channel' - -defineOptions({ name: 'WalletChannelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<any>({ - appId: '', - code: '', - status: undefined, - feeRate: 0, - remark: '', - config: { - name: 'mock-conf' - } -}) -const formRules = { - status: [{ required: true, message: '娓犻亾鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -} -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (appId, code) => { - dialogVisible.value = true - formLoading.value = true - resetForm(appId, code) - // 鍔犺浇鏁版嵁 - try { - const data = await ChannelApi.getChannel(appId, code) - - if (data && data.id) { - formData.value = data - formData.value.config = JSON.parse(data.config) - } - dialogTitle.value = !formData.value.id ? '鍒涘缓鏀粯娓犻亾' : '缂栬緫鏀粯娓犻亾' - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } as unknown as ChannelApi.ChannelVO - data.config = JSON.stringify(formData.value.config) - if (!data.id) { - await ChannelApi.createChannel(data) - message.success(t('common.createSuccess')) - } else { - await ChannelApi.updateChannel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = (appId, code) => { - formData.value = { - appId: appId, - code: code, - status: CommonStatusEnum.ENABLE, - remark: '', - feeRate: 0, - config: { - name: 'mock-conf' - } - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/pay/app/components/channel/WeixinChannelForm.vue b/src/views/pay/app/components/channel/WeixinChannelForm.vue deleted file mode 100644 index 3ab53e8..0000000 --- a/src/views/pay/app/components/channel/WeixinChannelForm.vue +++ /dev/null @@ -1,306 +0,0 @@ -<template> - <div> - <Dialog v-model="dialogVisible" :title="dialogTitle" @close="close" width="800px"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label-width="180px" label="娓犻亾璐圭巼" prop="feeRate"> - <el-input - v-model="formData.feeRate" - placeholder="璇疯緭鍏ユ笭閬撹垂鐜�" - clearable - :style="{ width: '100%' }" - > - <template #append>%</template> - </el-input> - </el-form-item> - <el-form-item label-width="180px" label="寰俊 APPID" prop="config.appId"> - <el-input - v-model="formData.config.appId" - placeholder="璇疯緭鍏ュ井淇� APPID" - clearable - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label="鍟嗘埛鍙�" prop="config.mchId"> - <el-input v-model="formData.config.mchId" :style="{ width: '100%' }" /> - </el-form-item> - <el-form-item label-width="180px" label="娓犻亾鐘舵��" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="parseInt(dict.value)" - :label="parseInt(dict.value)" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label-width="180px" label="API 鐗堟湰" prop="config.apiVersion"> - <el-radio-group v-model="formData.config.apiVersion"> - <el-radio label="v2">v2</el-radio> - <el-radio label="v3">v3</el-radio> - </el-radio-group> - </el-form-item> - <div v-if="formData.config.apiVersion === 'v2'"> - <el-form-item label-width="180px" label="鍟嗘埛瀵嗛挜" prop="config.mchKey"> - <el-input - v-model="formData.config.mchKey" - placeholder="璇疯緭鍏ュ晢鎴峰瘑閽�" - clearable - /> - </el-form-item> - <el-form-item - label-width="180px" - label="apiclient_cert.p12 璇佷功" - prop="config.keyContent" - > - <el-input - v-model="formData.config.keyContent" - type="textarea" - placeholder="璇蜂笂浼� apiclient_cert.p12 璇佷功" - readonly - :autosize="{ minRows: 8, maxRows: 8 }" - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label=""> - <el-upload - :limit="1" - accept=".p12" - action="" - :before-upload="p12FileBeforeUpload" - :http-request="keyContentUpload" - > - <el-button type="primary"> - <Icon icon="ep:upload" class="mr-5px" /> - 鐐瑰嚮涓婁紶 - </el-button> - </el-upload> - </el-form-item> - </div> - <div v-if="formData.config.apiVersion === 'v3'"> - <el-form-item label-width="180px" label="API V3 瀵嗛挜" prop="config.apiV3Key"> - <el-input - v-model="formData.config.apiV3Key" - placeholder="璇疯緭鍏� API V3 瀵嗛挜" - clearable - /> - </el-form-item> - <el-form-item - label-width="180px" - label="apiclient_key.pem 璇佷功" - prop="config.privateKeyContent" - > - <el-input - v-model="formData.config.privateKeyContent" - type="textarea" - placeholder="璇蜂笂浼� apiclient_key.pem 璇佷功" - readonly - :autosize="{ minRows: 8, maxRows: 8 }" - :style="{ width: '100%' }" - /> - </el-form-item> - <el-form-item label-width="180px" label="" prop="privateKeyContentFile"> - <el-upload - ref="privateKeyContentFile" - :limit="1" - accept=".pem" - action="" - :before-upload="pemFileBeforeUpload" - :http-request="privateKeyContentUpload" - > - <el-button type="primary"> - <Icon icon="ep:upload" class="mr-5px" /> - 鐐瑰嚮涓婁紶 - </el-button> - </el-upload> - </el-form-item> - <el-form-item label-width="180px" label="璇佷功搴忓垪鍙�" prop="config.certSerialNo"> - <el-input - v-model="formData.config.certSerialNo" - placeholder="璇疯緭鍏ヨ瘉涔﹀簭鍒楀彿" - clearable - /> - </el-form-item> - </div> - <el-form-item label-width="180px" label="澶囨敞" prop="remark"> - <el-input v-model="formData.remark" :style="{ width: '100%' }" /> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> - </div> -</template> -<script lang="ts" setup> -import { CommonStatusEnum } from '@/utils/constants' -import { DICT_TYPE, getDictOptions } from '@/utils/dict' -import * as ChannelApi from '@/api/pay/channel' - -defineOptions({ name: 'WeixinChannelForm' }) - -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formData = ref<any>({ - appId: '', - code: '', - status: undefined, - feeRate: undefined, - remark: '', - config: { - appId: '', - mchId: '', - apiVersion: '', - mchKey: '', - keyContent: '', - privateKeyContent: '', - certSerialNo: '', - apiV3Key: '' - } -}) -const formRules = { - feeRate: [{ required: true, message: '璇疯緭鍏ユ笭閬撹垂鐜�', trigger: 'blur' }], - status: [{ required: true, message: '娓犻亾鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }], - 'config.mchId': [{ required: true, message: '璇蜂紶鍏ュ晢鎴峰彿', trigger: 'blur' }], - 'config.appId': [{ required: true, message: '璇疯緭鍏ュ叕浼楀彿APPID', trigger: 'blur' }], - 'config.apiVersion': [{ required: true, message: 'API鐗堟湰涓嶈兘涓虹┖', trigger: 'blur' }], - 'config.mchKey': [{ required: true, message: '璇疯緭鍏ュ晢鎴峰瘑閽�', trigger: 'blur' }], - 'config.keyContent': [ - { required: true, message: '璇蜂笂浼� apiclient_cert.p12 璇佷功', trigger: 'blur' } - ], - 'config.privateKeyContent': [ - { required: true, message: '璇蜂笂浼� apiclient_key.pem 璇佷功', trigger: 'blur' } - ], - 'config.certSerialNo': [ - { required: true, message: '璇疯緭鍏ヨ瘉涔﹀簭鍒楀彿', trigger: 'blur' } - ], - 'config.apiV3Key': [{ required: true, message: '璇蜂笂浼� api V3 瀵嗛挜鍊�', trigger: 'blur' }] -} -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (appId, code) => { - dialogVisible.value = true - formLoading.value = true - resetForm(appId, code) - // 鍔犺浇鏁版嵁 - try { - const data = await ChannelApi.getChannel(appId, code) - if (data && data.id) { - formData.value = data - formData.value.config = JSON.parse(data.config) - } - dialogTitle.value = !formData.value.id ? '鍒涘缓鏀粯娓犻亾' : '缂栬緫鏀粯娓犻亾' - } finally { - formLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } as unknown as ChannelApi.ChannelVO - data.config = JSON.stringify(formData.value.config) - if (!data.id) { - await ChannelApi.createChannel(data) - message.success(t('common.createSuccess')) - } else { - await ChannelApi.updateChannel(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = (appId, code) => { - formData.value = { - appId: appId, - code: code, - status: CommonStatusEnum.ENABLE, - feeRate: undefined, - remark: '', - config: { - appId: '', - mchId: '', - apiVersion: '', - mchKey: '', - keyContent: '', - privateKeyContent: '', - certSerialNo: '', - apiV3Key: '' - } - } - formRef.value?.resetFields() -} - -/** - * apiclient_cert.p12銆乤piclient_key.pem 涓婁紶鍓嶇殑鏍¢獙 - */ -const fileBeforeUpload = (file, fileAccept) => { - let format = '.' + file.name.split('.')[1] - if (format !== fileAccept) { - debugger - message.error('璇蜂笂浼犳寚瀹氭牸寮�"' + fileAccept + '"鏂囦欢') - return false - } - let isRightSize = file.size / 1024 / 1024 < 2 - if (!isRightSize) { - message.error('鏂囦欢澶у皬瓒呰繃 2MB') - } - return isRightSize -} - -const p12FileBeforeUpload = (file) => { - fileBeforeUpload(file, '.p12') -} - -const pemFileBeforeUpload = (file) => { - fileBeforeUpload(file, '.pem') -} - -/** - * 璇诲彇 apiclient_key.pem 鍒� privateKeyContent 瀛楁 - */ -const privateKeyContentUpload = async (event) => { - const readFile = new FileReader() - readFile.onload = (e: any) => { - formData.value.config.privateKeyContent = e.target.result - } - readFile.readAsText(event.file) -} - -/** - * 璇诲彇 apiclient_cert.p12 鍒� keyContent 瀛楁 - */ -const keyContentUpload = async (event) => { - const readFile = new FileReader() - readFile.onload = (e: any) => { - formData.value.config.keyContent = e.target.result.split(',')[1] - } - readFile.readAsDataURL(event.file) // 璇绘垚 base64 -} -</script> diff --git a/src/views/pay/app/index.vue b/src/views/pay/app/index.vue deleted file mode 100644 index 6b60d9b..0000000 --- a/src/views/pay/app/index.vue +++ /dev/null @@ -1,364 +0,0 @@ -<template> - <doc-alert title="鏀粯鍔熻兘寮�鍚�" url="https://doc.iocoder.cn/pay/build/" /> - <!-- 鎼滅储 --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="搴旂敤鍚�" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ簲鐢ㄥ悕" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨寮�鍚姸鎬�" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 鎼滅储 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 閲嶇疆 - </el-button> - <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['pay:app:create']"> - <Icon icon="ep:plus" class="mr-5px" /> - 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="搴旂敤缂栧彿" align="center" prop="id" /> - <el-table-column label="搴旂敤鍚�" align="center" prop="name" /> - <el-table-column label="寮�鍚姸鎬�" align="center" prop="status"> - <template #default="scope"> - <el-switch - v-model="scope.row.status" - :active-value="0" - :inactive-value="1" - @change="handleStatusChange(scope.row)" - /> - </template> - </el-table-column> - <el-table-column label="鏀粯瀹濋厤缃�" align="center"> - <el-table-column - :label="channel.name" - align="center" - v-for="channel in alipayChannels" - :key="channel.code" - > - <template #default="scope"> - <el-button - type="success" - v-if="isChannelExists(scope.row.channelCodes, channel.code)" - @click="openChannelForm(scope.row, channel.code)" - circle - > - <Icon icon="ep:check" /> - </el-button> - <el-button - v-else - type="danger" - circle - @click="openChannelForm(scope.row, channel.code)" - > - <Icon icon="ep:close" /> - </el-button> - </template> - </el-table-column> - </el-table-column> - <el-table-column label="寰俊閰嶇疆" align="center"> - <el-table-column - :label="channel.name" - align="center" - v-for="channel in wxChannels" - :key="channel.code" - > - <template #default="scope"> - <el-button - type="success" - v-if="isChannelExists(scope.row.channelCodes, channel.code)" - @click="openChannelForm(scope.row, channel.code)" - circle - > - <Icon icon="ep:check" /> - </el-button> - <el-button - v-else - type="danger" - circle - @click="openChannelForm(scope.row, channel.code)" - > - <Icon icon="ep:close" /> - </el-button> - </template> - </el-table-column> - </el-table-column> - <el-table-column label="閽卞寘鏀粯閰嶇疆" align="center"> - <el-table-column :label="PayChannelEnum.WALLET.name" align="center"> - <template #default="scope"> - <el-button - type="success" - circle - v-if="isChannelExists(scope.row.channelCodes, PayChannelEnum.WALLET.code)" - @click="openChannelForm(scope.row, PayChannelEnum.WALLET.code)" - > - <Icon icon="ep:check" /> - </el-button> - <el-button - v-else - type="danger" - circle - @click="openChannelForm(scope.row, PayChannelEnum.WALLET.code)" - > - <Icon icon="ep:close" /> - </el-button> - </template> - </el-table-column> - </el-table-column> - <el-table-column label="妯℃嫙鏀粯閰嶇疆" align="center"> - <el-table-column :label="PayChannelEnum.MOCK.name" align="center"> - <template #default="scope"> - <el-button - type="success" - circle - v-if="isChannelExists(scope.row.channelCodes, PayChannelEnum.MOCK.code)" - @click="openChannelForm(scope.row, PayChannelEnum.MOCK.code)" - > - <Icon icon="ep:check" /> - </el-button> - <el-button - v-else - type="danger" - circle - @click="openChannelForm(scope.row, PayChannelEnum.MOCK.code)" - > - <Icon icon="ep:close" /> - </el-button> - </template> - </el-table-column> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" min-width="110" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['pay:app:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['pay:app:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <AppForm ref="formRef" @success="getList" /> - <AlipayChannelForm ref="alipayFormRef" @success="getList" /> - <WeixinChannelForm ref="weixinFormRef" @success="getList" /> - <MockChannelForm ref="mockFormRef" @success="getList" /> - <WalletChannelForm ref="walletFormRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as AppApi from '@/api/pay/app' -import AppForm from './components/AppForm.vue' -import { CommonStatusEnum, PayChannelEnum } from '@/utils/constants' -import AlipayChannelForm from './components/channel/AlipayChannelForm.vue' -import WeixinChannelForm from './components/channel/WeixinChannelForm.vue' -import MockChannelForm from './components/channel/MockChannelForm.vue' -import WalletChannelForm from './components/channel/WalletChannelForm.vue' - -defineOptions({ name: 'PayApp' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: undefined, - status: undefined, - remark: undefined, - payNotifyUrl: undefined, - refundNotifyUrl: undefined, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -const alipayChannels = [ - PayChannelEnum.ALIPAY_APP, - PayChannelEnum.ALIPAY_PC, - PayChannelEnum.ALIPAY_WAP, - PayChannelEnum.ALIPAY_QR, - PayChannelEnum.ALIPAY_BAR -] - -const wxChannels = [ - PayChannelEnum.WX_LITE, - PayChannelEnum.WX_PUB, - PayChannelEnum.WX_APP, - PayChannelEnum.WX_NATIVE, - PayChannelEnum.WX_WAP, - PayChannelEnum.WX_BAR, -] - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await AppApi.getAppPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 搴旂敤鐘舵�佷慨鏀� */ -const handleStatusChange = async (row: any) => { - let text = row.status === CommonStatusEnum.ENABLE ? '鍚敤' : '鍋滅敤' - try { - await message.confirm('纭瑕�"' + text + '""' + row.name + '"搴旂敤鍚�?') - await AppApi.changeAppStatus({ id: row.id, status: row.status }) - message.success(text + '鎴愬姛') - } catch { - row.status = - row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE - } -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await AppApi.deleteApp(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} - -/** - * 鏍规嵁娓犻亾缂栫爜鍒ゆ柇娓犻亾鍒楄〃涓槸鍚﹀瓨鍦� - * - * @param channels 娓犻亾鍒楄〃 - * @param channelCode 娓犻亾缂栫爜 - */ -const isChannelExists = (channels, channelCode) => { - if (!channels) { - return false - } - return channels.indexOf(channelCode) !== -1 -} - -/** - * 鏂板鏀粯娓犻亾淇℃伅 - */ -const alipayFormRef = ref() -const weixinFormRef = ref() -const mockFormRef = ref() -const walletFormRef = ref() -const channelParam = reactive({ - appId: null, // 搴旂敤 ID - payCode: null // 娓犻亾缂栫爜 -}) -const openChannelForm = async (row, payCode) => { - channelParam.appId = row.id - channelParam.payCode = payCode - if (payCode.indexOf('alipay_') === 0) { - alipayFormRef.value.open(row.id, payCode) - return - } - if (payCode.indexOf('wx_') === 0) { - weixinFormRef.value.open(row.id, payCode) - return - } - if (payCode.indexOf('mock') === 0) { - mockFormRef.value.open(row.id, payCode) - } - if (payCode.indexOf('wallet') === 0) { - mockFormRef.value.open(row.id, payCode) - } -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> diff --git a/src/views/pay/cashier/index.vue b/src/views/pay/cashier/index.vue deleted file mode 100644 index 12723db..0000000 --- a/src/views/pay/cashier/index.vue +++ /dev/null @@ -1,482 +0,0 @@ -<template> - <!-- 鏀粯淇℃伅 --> - <el-card v-loading="loading"> - <el-descriptions title="鏀粯淇℃伅" :column="3" border> - <el-descriptions-item label="鏀粯鍗曞彿">{{ payOrder.id }}</el-descriptions-item> - <el-descriptions-item label="鍟嗗搧鏍囬">{{ payOrder.subject }}</el-descriptions-item> - <el-descriptions-item label="鍟嗗搧鍐呭">{{ payOrder.body }}</el-descriptions-item> - <el-descriptions-item label="鏀粯閲戦"> - 锟{ (payOrder.price / 100.0).toFixed(2) }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(payOrder.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="杩囨湡鏃堕棿"> - {{ formatDate(payOrder.expireTime) }} - </el-descriptions-item> - </el-descriptions> - </el-card> - - <!-- 鏀粯閫夋嫨妗� --> - <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="鎻愪氦鏀粯涓�..."> - <!-- 鏀粯瀹� --> - <el-descriptions title="閫夋嫨鏀粯瀹濇敮浠�" /> - <div class="pay-channel-container"> - <div - class="box" - v-for="channel in channelsAlipay" - :key="channel.code" - @click="submit(channel.code)" - > - <img :src="channel.icon" /> - <div class="title">{{ channel.name }}</div> - </div> - </div> - <!-- 寰俊鏀粯 --> - <el-descriptions title="閫夋嫨寰俊鏀粯" style="margin-top: 20px" /> - <div class="pay-channel-container"> - <div - class="box" - v-for="channel in channelsWechat" - :key="channel.code" - @click="submit(channel.code)" - > - <img :src="channel.icon" /> - <div class="title">{{ channel.name }}</div> - </div> - </div> - <!-- 鍏跺畠鏀粯 --> - <el-descriptions title="閫夋嫨鍏跺畠鏀粯" style="margin-top: 20px" /> - <div class="pay-channel-container"> - <div - class="box" - v-for="channel in channelsMock" - :key="channel.code" - @click="submit(channel.code)" - > - <img :src="channel.icon" /> - <div class="title">{{ channel.name }}</div> - </div> - </div> - </el-card> - - <!-- 灞曠ず褰㈠紡锛氫簩缁寸爜 URL --> - <Dialog - :title="qrCode.title" - v-model="qrCode.visible" - width="350px" - append-to-body - :close-on-press-escape="false" - > - <Qrcode :text="qrCode.url" :width="310" /> - </Dialog> - - <!-- 灞曠ず褰㈠紡锛欱arCode 鏉″舰鐮� --> - <Dialog - :title="barCode.title" - v-model="barCode.visible" - width="500px" - append-to-body - :close-on-press-escape="false" - > - <el-form ref="form" label-width="80px"> - <el-row> - <el-col :span="24"> - <el-form-item label="鏉″舰鐮�" prop="name"> - <el-input v-model="barCode.value" placeholder="璇疯緭鍏ユ潯褰㈢爜" required /> - </el-form-item> - </el-col> - <el-col :span="24"> - <div style="text-align: right"> - 鎴栦娇鐢� - <el-link - type="danger" - target="_blank" - href="https://baike.baidu.com/item/鏉$爜鏀粯/10711903" - > - (鎵爜鏋�/鎵爜鐩�) - </el-link> - 鎵爜 - </div> - </el-col> - </el-row> - </el-form> - <template #footer> - <el-button - type="primary" - @click="submit0(barCode.channelCode)" - :disabled="barCode.value.length === 0" - > - 纭鏀粯 - </el-button> - <el-button @click="barCode.visible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> - -<script lang="ts" setup> -import { Qrcode } from '@/components/Qrcode' -import * as PayOrderApi from '@/api/pay/order' -import { PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum } from '@/utils/constants' -import { formatDate } from '@/utils/formatTime' -import { useTagsViewStore } from '@/store/modules/tagsView' - -// 瀵煎叆鍥炬爣 -import svg_alipay_pc from '@/assets/svgs/pay/icon/alipay_pc.svg' -import svg_alipay_wap from '@/assets/svgs/pay/icon/alipay_wap.svg' -import svg_alipay_app from '@/assets/svgs/pay/icon/alipay_app.svg' -import svg_alipay_qr from '@/assets/svgs/pay/icon/alipay_qr.svg' -import svg_alipay_bar from '@/assets/svgs/pay/icon/alipay_bar.svg' -import svg_wx_pub from '@/assets/svgs/pay/icon/wx_pub.svg' -import svg_wx_lite from '@/assets/svgs/pay/icon/wx_lite.svg' -import svg_wx_app from '@/assets/svgs/pay/icon/wx_app.svg' -import svg_wx_native from '@/assets/svgs/pay/icon/wx_native.svg' -import svg_wx_bar from '@/assets/svgs/pay/icon/wx_bar.svg' -import svg_mock from '@/assets/svgs/pay/icon/mock.svg' - -defineOptions({ name: 'PayCashier' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const route = useRoute() // 璺敱 -const { push, currentRoute } = useRouter() // 璺敱 -const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔 - -const id = ref(undefined) // 鏀粯鍗曞彿 -const returnUrl = ref<string | undefined>(undefined) // 鏀粯瀹岀殑鍥炶皟鍦板潃 -const loading = ref(false) // 鏀粯淇℃伅鐨� loading -const payOrder = ref({}) // 鏀粯淇℃伅 -const channelsAlipay = [ - { - name: '鏀粯瀹� PC 缃戠珯鏀粯', - icon: svg_alipay_pc, - code: 'alipay_pc' - }, - { - name: '鏀粯瀹� Wap 缃戠珯鏀粯', - icon: svg_alipay_wap, - code: 'alipay_wap' - }, - { - name: '鏀粯瀹� App 缃戠珯鏀粯', - icon: svg_alipay_app, - code: 'alipay_app' - }, - { - name: '鏀粯瀹濇壂鐮佹敮浠�', - icon: svg_alipay_qr, - code: 'alipay_qr' - }, - { - name: '鏀粯瀹濇潯鐮佹敮浠�', - icon: svg_alipay_bar, - code: 'alipay_bar' - } -] -const channelsWechat = [ - { - name: '寰俊鍏紬鍙锋敮浠�', - icon: svg_wx_pub, - code: 'wx_pub' - }, - { - name: '寰俊灏忕▼搴忔敮浠�', - icon: svg_wx_lite, - code: 'wx_lite' - }, - { - name: '寰俊 App 鏀粯', - icon: svg_wx_app, - code: 'wx_app' - }, - { - name: '寰俊鎵爜鏀粯', - icon: svg_wx_native, - code: 'wx_native' - }, - { - name: '寰俊鏉$爜鏀粯', - icon: svg_wx_bar, - code: 'wx_bar' - } -] -const channelsMock = [ - { - name: '妯℃嫙鏀粯', - icon: svg_mock, - code: 'mock' - } -] - -const submitLoading = ref(false) // 鎻愪氦鏀粯鐨� loading -const interval = ref<any>(undefined) // 瀹氭椂浠诲姟锛岃疆璇㈡槸鍚﹀畬鎴愭敮浠� -const qrCode = ref({ - // 灞曠ず褰㈠紡锛氫簩缁寸爜 - url: '', - title: '', - visible: false -}) -const barCode = ref({ - // 灞曠ず褰㈠紡锛氭潯褰㈢爜 - channelCode: '', - value: '', - title: '', - visible: false -}) - -/** 鑾峰緱鏀粯淇℃伅 */ -const getDetail = async () => { - // 1.1 鏈紶閫掕鍗曠紪鍙� - if (!id.value) { - message.error('鏈紶閫掓敮浠樺崟鍙凤紝鏃犳硶鏌ョ湅瀵瑰簲鐨勬敮浠樹俊鎭�') - goReturnUrl('cancel') - return - } - const data = await PayOrderApi.getOrder(id.value) - payOrder.value = data - // 1.2 鏃犳硶鏌ヨ鍒版敮浠樹俊鎭� - if (!data) { - message.error('鏀粯璁㈠崟涓嶅瓨鍦紝璇锋鏌ワ紒') - goReturnUrl('cancel') - return - } - // 1.3 濡傛灉宸叉敮浠樸�佹垨鑰呭凡鍏抽棴锛屽垯鐩存帴璺宠浆 - if (data.status === PayOrderStatusEnum.SUCCESS.status) { - message.success('鏀粯鎴愬姛') - goReturnUrl('success') - return - } else if (data.status === PayOrderStatusEnum.CLOSED.status) { - message.error('鏃犳硶鏀粯锛屽師鍥狅細璁㈠崟宸插叧闂�') - goReturnUrl('close') - return - } -} - -/** 鎻愪氦鏀粯 */ -const submit = (channelCode) => { - // 鏉″舰鐮佹敮浠橈紝闇�瑕佺壒娈婂鐞� - if (channelCode === PayChannelEnum.ALIPAY_BAR.code) { - barCode.value = { - channelCode: channelCode, - value: '', - title: '鈥滄敮浠樺疂鈥濇潯鐮佹敮浠�', - visible: true - } - return - } - if (channelCode === PayChannelEnum.WX_BAR.code) { - barCode.value = { - channelCode: channelCode, - value: '', - title: '鈥滃井淇♀�濇潯鐮佹敮浠�', - visible: true - } - return - } - - // 寰俊鍏紬鍙枫�佸皬绋嬪簭鏀粯锛屾棤娉曞湪 PC 缃戦〉涓繘琛� - if (channelCode === PayChannelEnum.WX_PUB.code) { - message.error('寰俊鍏紬鍙锋敮浠橈細涓嶆敮鎸� PC 缃戠珯') - return - } - if (channelCode === PayChannelEnum.WX_LITE.code) { - message.error('寰俊灏忕▼搴忥細涓嶆敮鎸� PC 缃戠珯') - return - } - - // 榛樿鐨勬彁浜ゅ鐞� - submit0(channelCode) -} - -const submit0 = async (channelCode) => { - submitLoading.value = true - try { - const formData = { - id: id.value, - channelCode: channelCode, - returnUrl: location.href, // 鏀粯鎴愬姛鍚庯紝鏀粯娓犻亾璺宠浆鍥炲綋鍓嶉〉锛涘啀鐢卞綋鍓嶉〉锛岃烦杞洖 {@link returnUrl} 瀵瑰簲鐨勫湴鍧� - ...buildSubmitParam(channelCode) - } - const data = await PayOrderApi.submitOrder(formData) - // 鐩存帴杩斿洖宸叉敮浠樼殑鎯呭喌锛屼緥濡傝鎵爜鏀粯 - if (data.status === PayOrderStatusEnum.SUCCESS.status) { - clearQueryInterval() - message.success('鏀粯鎴愬姛锛�') - goReturnUrl('success') - return - } - - // 灞曠ず瀵瑰簲鐨勭晫闈� - if (data.displayMode === PayDisplayModeEnum.URL.mode) { - displayUrl(channelCode, data) - } else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) { - displayQrCode(channelCode, data) - } else if (data.displayMode === PayDisplayModeEnum.APP.mode) { - displayApp(channelCode) - } - - // 鎵撳紑杞浠诲姟 - createQueryInterval() - } finally { - submitLoading.value = false - } -} - -/** 鏋勫缓鎻愪氦鏀粯鐨勯澶栧弬鏁� */ -const buildSubmitParam = (channelCode) => { - // 鈶� 鏀粯瀹� BarCode 鏀粯鏃讹紝闇�瑕佷紶閫� authCode 鏉″舰鐮� - if (channelCode === PayChannelEnum.ALIPAY_BAR.code) { - return { - channelExtras: { - auth_code: barCode.value.value - } - } - } - // 鈶� 寰俊 BarCode 鏀粯鏃讹紝闇�瑕佷紶閫� authCode 鏉″舰鐮� - if (channelCode === PayChannelEnum.WX_BAR.code) { - return { - channelExtras: { - authCode: barCode.value.value - } - } - } - return {} -} - -/** 鎻愪氦鏀粯鍚庯紝URL 鐨勫睍绀哄舰寮� */ -const displayUrl = (_channelCode, data) => { - location.href = data.displayContent - submitLoading.value = false -} - -/** 鎻愪氦鏀粯鍚庯紙鎵爜鏀粯锛� */ -const displayQrCode = (channelCode, data) => { - let title = '璇蜂娇鐢ㄦ墜鏈烘祻瑙堝櫒鈥滄壂涓�鎵��' - if (channelCode === PayChannelEnum.ALIPAY_WAP.code) { - // 鑰冭檻鍒� WAP 娴嬭瘯锛屾墍浠ュ紩瀵兼墜鏈烘祻瑙堝櫒鎼� - } else if (channelCode.indexOf('alipay_') === 0) { - title = '璇蜂娇鐢ㄦ敮浠樺疂鈥滄壂涓�鎵�濇壂鐮佹敮浠�' - } else if (channelCode.indexOf('wx_') === 0) { - title = '璇蜂娇鐢ㄥ井淇♀�滄壂涓�鎵�濇壂鐮佹敮浠�' - } - qrCode.value = { - title: title, - url: data.displayContent, - visible: true - } - submitLoading.value = false -} - -/** 鎻愪氦鏀粯鍚庯紙App锛� */ -const displayApp = (channelCode) => { - if (channelCode === PayChannelEnum.ALIPAY_APP.code) { - message.error('鏀粯瀹� App 鏀粯锛氭棤娉曞湪缃戦〉鏀粯锛�') - } - if (channelCode === PayChannelEnum.WX_APP.code) { - message.error('寰俊 App 鏀粯锛氭棤娉曞湪缃戦〉鏀粯锛�') - } - submitLoading.value = false -} - -/** 杞鏌ヨ浠诲姟 */ -const createQueryInterval = () => { - if (interval.value) { - return - } - interval.value = setInterval(async () => { - const data = await PayOrderApi.getOrder(id.value) - // 宸叉敮浠� - if (data.status === PayOrderStatusEnum.SUCCESS.status) { - clearQueryInterval() - message.success('鏀粯鎴愬姛锛�') - goReturnUrl('success') - } - // 宸插彇娑� - if (data.status === PayOrderStatusEnum.CLOSED.status) { - clearQueryInterval() - message.error('鏀粯宸插叧闂紒') - goReturnUrl('close') - } - }, 1000 * 2) -} - -/** 娓呯┖鏌ヨ浠诲姟 */ -const clearQueryInterval = () => { - // 娓呯┖鍚勭寮圭獥 - qrCode.value = { - title: '', - url: '', - visible: false - } - // 娓呯┖浠诲姟 - clearInterval(interval.value) - interval.value = undefined -} - -/** - * 鍥炲埌涓氬姟鐨� URL - * - * @param payResult 鏀粯缁撴灉 - * 鈶� success锛氭敮浠樻垚鍔� - * 鈶� cancel锛氬彇娑堟敮浠� - * 鈶� close锛氭敮浠樺凡鍏抽棴 - */ -const goReturnUrl = (payResult) => { - // 娓呯悊浠诲姟 - clearQueryInterval() - - // 鏈厤缃殑鎯呭喌涓嬶紝鍙兘鍏抽棴 - if (!returnUrl.value) { - delView(unref(currentRoute)) - return - } - - const url = - returnUrl.value.indexOf('?') >= 0 - ? returnUrl.value + '&payResult=' + payResult - : returnUrl.value + '?payResult=' + payResult - // 濡傛灉鏈夐厤缃紝涓旀槸 http 寮�澶达紝鍒欐祻瑙堝櫒璺宠浆 - if (returnUrl.value.indexOf('http') === 0) { - location.href = url - } else { - delView(unref(currentRoute)) - push({ - path: url - }) - } -} - -/** 鍒濆鍖� */ -onMounted(() => { - id.value = route.query.id - if (route.query.returnUrl) { - returnUrl.value = decodeURIComponent(route.query.returnUrl) - } - getDetail() -}) -</script> - -<style lang="scss" scoped> -.pay-channel-container { - display: flex; - margin-top: -10px; - - .box { - width: 160px; - padding-top: 10px; - padding-bottom: 5px; - margin-right: 10px; - text-align: center; - cursor: pointer; - border: 1px solid #e6ebf5; - - img { - width: 40px; - height: 40px; - } - - .title { - padding-top: 5px; - } - } -} -</style> diff --git a/src/views/pay/demo/order/index.vue b/src/views/pay/demo/order/index.vue deleted file mode 100644 index 32f0de1..0000000 --- a/src/views/pay/demo/order/index.vue +++ /dev/null @@ -1,240 +0,0 @@ -<template> - <doc-alert title="鏀粯瀹濇敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/alipay-pay-demo/" /> - <doc-alert title="鏀粯瀹濄�佸井淇¢��娆炬帴鍏�" url="https://doc.iocoder.cn/pay/refund-demo/" /> - <doc-alert title="寰俊鍏紬鍙锋敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/wx-pub-pay-demo/" /> - <doc-alert title="寰俊灏忕▼搴忔敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/" /> - - <!-- 鎿嶄綔宸ュ叿鏍� --> - <el-row :gutter="10" class="mb8"> - <el-col :span="1.5"> - <el-button type="primary" plain @click="openForm"><Icon icon="ep:plus" />鍙戣捣璁㈠崟</el-button> - </el-col> - </el-row> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="璁㈠崟缂栧彿" align="center" prop="id" /> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="userId" /> - <el-table-column label="鍟嗗搧鍚嶅瓧" align="center" prop="spuName" /> - <el-table-column label="鏀粯浠锋牸" align="center" prop="price"> - <template #default="scope"> - <span>锟{ (scope.row.price / 100.0).toFixed(2) }}</span> - </template> - </el-table-column> - <el-table-column label="閫�娆鹃噾棰�" align="center" prop="refundPrice"> - <template #default="scope"> - <span>锟{ (scope.row.refundPrice / 100.0).toFixed(2) }}</span> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏀粯鍗曞彿" align="center" prop="payOrderId" /> - <el-table-column label="鏄惁鏀粯" align="center" prop="payStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.payStatus" /> - </template> - </el-table-column> - <el-table-column - label="鏀粯鏃堕棿" - align="center" - prop="payTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="閫�娆炬椂闂�" align="center" prop="refundTime" width="180"> - <template #default="scope"> - <span v-if="scope.row.refundTime">{{ formatDate(scope.row.refundTime) }}</span> - <span v-else-if="scope.row.payRefundId">閫�娆句腑锛岀瓑寰呴��娆剧粨鏋�</span> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> - <template #default="scope"> - <el-button link type="primary" @click="handlePay(scope.row)" v-if="!scope.row.payStatus"> - 鍓嶅線鏀粯 - </el-button> - <el-button - link - type="danger" - @click="handleRefund(scope.row)" - v-if="scope.row.payStatus && !scope.row.payRefundId" - > - 鍙戣捣閫�娆� - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉缁勪欢 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 瀵硅瘽妗�(娣诲姞 / 淇敼) --> - <Dialog title="鍙戣捣璁㈠崟" v-model="dialogVisible" width="500px"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="80px" - > - <el-form-item label="鍟嗗搧" prop="spuId"> - <el-select - v-model="formData.spuId" - placeholder="璇疯緭鍏ヤ笅鍗曞晢鍝�" - clearable - style="width: 380px" - > - <el-option v-for="item in spus" :key="item.id" :label="item.name" :value="item.id"> - <span style="float: left">{{ item.name }}</span> - <span style="float: right; font-size: 13px; color: #8492a6"> - 锟{ (item.price / 100.0).toFixed(2) }} - </span> - </el-option> - </el-select> - </el-form-item> - </el-form> - <template #footer> - <el-button :disabled="formLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script lang="ts" setup name="PayDemoOrder"> -import * as PayDemoApi from '@/api/pay/demo' -import { dateFormatter, formatDate } from '@/utils/formatTime' -import { DICT_TYPE } from '@/utils/dict' - -const { t } = useI18n() // 鍥介檯鍖� -const router = useRouter() // 璺敱瀵硅薄 -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -// 鏌ヨ鏉′欢 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10 -}) - -const formRef = ref() - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PayDemoApi.getDemoOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鏀粯鎸夐挳鎿嶄綔 */ -const handlePay = (row: any) => { - router.push({ - name: 'PayCashier', - query: { - id: row.payOrderId, - returnUrl: encodeURIComponent('/pay/demo/order?id=' + row.id) - } - }) -} - -/** 閫�娆炬寜閽搷浣� */ -const handleRefund = async (row: any) => { - const id = row.id - try { - await message.confirm('鏄惁纭閫�娆剧紪鍙蜂负"' + id + '"鐨勭ず渚嬭鍗�?') - await PayDemoApi.refundDemoOrder(id) - await getList() - message.success('鍙戣捣閫�娆炬垚鍔燂紒') - } catch {} -} - -// ========== 寮圭獥 ========== - -// 鍟嗗搧鏁扮粍 -const spus = ref([ - { - id: 1, - name: '鍗庝负鎵嬫満', - price: 1 - }, - { - id: 2, - name: '灏忕背鐢佃', - price: 10 - }, - { - id: 3, - name: '鑻规灉鎵嬭〃', - price: 100 - }, - { - id: 4, - name: '鍗庣绗旇鏈�', - price: 1000 - }, - { - id: 5, - name: '钄氭潵姹借溅', - price: 200000 - } -]) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const formData = ref<any>({}) // 琛ㄥ崟鏁版嵁 -const formRules = { - spuId: [{ required: true, message: '鍟嗗搧缂栧彿涓嶈兘涓虹┖', trigger: 'blur' }] -} - -/** 琛ㄥ崟閲嶇疆 */ -const reset = () => { - formData.value = { - spuId: undefined - } - formRef.value?.resetFields() -} - -/** 鏂板鎸夐挳鎿嶄綔 */ -const openForm = () => { - reset() - dialogVisible.value = true -} - -/** 鎻愪氦鎸夐挳 */ -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - await PayDemoApi.createDemoOrder(formData.value) - message.success(t('common.createSuccess')) - dialogVisible.value = false - } finally { - formLoading.value = false - getList() - } -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/pay/demo/transfer/DemoTransferForm.vue b/src/views/pay/demo/transfer/DemoTransferForm.vue deleted file mode 100644 index e5448f1..0000000 --- a/src/views/pay/demo/transfer/DemoTransferForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="800px"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="120px" - v-loading="formLoading" - > - <el-form-item label="杞处绫诲瀷" prop="type"> - <el-radio-group v-model="formData.type"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.PAY_TRANSFER_TYPE)" - :key="dict.value" - :label="dict.value" - :disabled="dict.value === 2 || dict.value === 3 || dict.value === 4" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="杞处閲戦(鍏�)" prop="price"> - <el-input-number - v-model="formData.price" - :min="0" - :precision="2" - :step="0.01" - placeholder="璇疯緭鍏ヨ浆璐﹂噾棰�" - style="width: 200px" - /> - </el-form-item> - <el-form-item label="鏀舵浜哄鍚�" prop="userName"> - <el-input v-model="formData.userName" placeholder="璇疯緭鍏ユ敹娆句汉濮撳悕" /> - </el-form-item> - <el-form-item v-show="formData.type === 1" label="鏀粯瀹濈櫥褰曡处鍙�" prop="alipayLogonId"> - <el-input v-model="formData.alipayLogonId" placeholder="璇疯緭鍏ユ敮浠樺疂鐧诲綍璐﹀彿" /> - </el-form-item> - <el-form-item v-show="formData.type === 2" label="寰俊 openid" prop="openid"> - <el-input v-model="formData.openid" placeholder="璇疯緭鍏ュ井淇� openid" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as DemoTransferApi from '@/api/pay/demo/transfer' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { yuanToFen } from '@/utils' -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - price: undefined, - type: undefined, - userName: undefined, - alipayLogonId: undefined, - openid: undefined -}) -const formRules = reactive({ - price: [{ required: true, message: '杞处閲戦涓嶈兘涓虹┖', trigger: 'blur' }], - type: [{ required: true, message: '杞处绫诲瀷涓嶈兘涓虹┖', trigger: 'change' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() -} -/** 鍏抽棴寮圭獥 */ -const close = async () => { - dialogVisible.value = false - resetForm() -} -defineExpose({ open, close }) // 鎻愪緵 open锛� close 鏂规硶锛岀敤浜庢墦寮�, 鍏抽棴寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } - data.price = yuanToFen(data.price) - if (formType.value === 'create') { - await DemoTransferApi.createDemoTransfer(data) - message.success(t('common.createSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - price: undefined, - userName: undefined, - alipayLogonId: undefined, - openid: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/pay/demo/transfer/index.vue b/src/views/pay/demo/transfer/index.vue deleted file mode 100644 index 44d07b1..0000000 --- a/src/views/pay/demo/transfer/index.vue +++ /dev/null @@ -1,159 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button type="primary" plain @click="openForm('create')" - ><Icon icon="ep:plus" />鍒涘缓涓氬姟杞处鍗� - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true"> - <el-table-column label="璁㈠崟缂栧彿" align="center" prop="id" /> - <el-table-column label="杞处绫诲瀷" align="center" prop="type" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_TRANSFER_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column label="杞处閲戦" align="center" prop="price"> - <template #default="scope"> - <span>锟{ (scope.row.price / 100.0).toFixed(2) }}</span> - </template> - </el-table-column> - <el-table-column label="鏀舵浜哄鍚�" align="center" prop="userName" width="120" /> - <el-table-column label="鏀粯瀹濈櫥褰曡处鍙�" align="center" prop="alipayLogonId" width="180" /> - <el-table-column label="寰俊 openid" align="center" prop="openid" width="120" /> - <el-table-column label="杞处鐘舵��" align="center" prop="transferStatus"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_TRANSFER_STATUS" :value="scope.row.transferStatus" /> - </template> - </el-table-column> - <el-table-column label="杞处鍗曞彿" align="center" prop="payTransferId" /> - <el-table-column label="鏀粯娓犻亾" align="center" prop="payChannelCode" /> - <el-table-column - label="杞处鏃堕棿" - align="center" - prop="transferTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column - label="鎿嶄綔" - align="center" - class-name="small-padding fixed-width" - width="100" - fixed="right" - > - <template #default="scope"> - <el-button - link - type="primary" - @click="handleTransfer(scope.row)" - v-if="scope.row.transferStatus === 0" - v-hasPermi="['pay:transfer:create']" - > - 鍙戣捣杞处 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <DemoTransferForm ref="demoFormRef" @success="getList" /> - <CreatePayTransfer ref="payTransferRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as DemoTransferApi from '@/api/pay/demo/transfer' -import * as PayTransferApi from '@/api/pay/transfer' -import DemoTransferForm from './DemoTransferForm.vue' -import CreatePayTransfer from '../../transfer/CreatePayTransfer.vue' -import { DICT_TYPE } from '@/utils/dict' -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10 -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -let payTransfer = { - appId: undefined, - merchantTransferId: undefined, - type: undefined, - price: undefined, - subject: undefined, - userName: undefined, - alipayLogonId: undefined, - openid: undefined -} as PayTransferApi.TransferVO // 浼犻�掔粰杞处璁㈠崟鐨勬暟鎹� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await DemoTransferApi.getDemoTransferPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 鍒涘缓涓氬姟杞处鍗曟搷浣� */ -const demoFormRef = ref() -const payTransferRef = ref() -const openForm = (type: string) => { - demoFormRef.value.open(type) -} - -/** 鍙戣捣杞处鎿嶄綔 */ -const handleTransfer = (row: any) => { - payTransfer = { ...row } - payTransfer.merchantTransferId = row.id.toString() - payTransfer.subject = '绀轰緥杞处' - payTransferRef.value.showPayTransfer(payTransfer) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/pay/notify/NotifyDetail.vue b/src/views/pay/notify/NotifyDetail.vue deleted file mode 100644 index 938a3ee..0000000 --- a/src/views/pay/notify/NotifyDetail.vue +++ /dev/null @@ -1,86 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="閫氱煡璇︽儏" width="50%"> - <el-descriptions :column="2"> - <el-descriptions-item label="鍟嗘埛璁㈠崟缂栧彿"> - <el-tag>{{ detailData.merchantOrderId }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="閫氱煡鐘舵��"> - <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="detailData.status" /> - </el-descriptions-item> - - <el-descriptions-item label="搴旂敤缂栧彿">{{ detailData.appId }}</el-descriptions-item> - <el-descriptions-item label="搴旂敤鍚嶇О">{{ detailData.appName }}</el-descriptions-item> - - <el-descriptions-item label="鍏宠仈缂栧彿">{{ detailData.dataId }}</el-descriptions-item> - <el-descriptions-item label="閫氱煡绫诲瀷"> - <dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="detailData.type" /> - </el-descriptions-item> - - <el-descriptions-item label="閫氱煡娆℃暟">{{ detailData.notifyTimes }}</el-descriptions-item> - <el-descriptions-item label="鏈�澶ч�氱煡娆℃暟"> - {{ detailData.maxNotifyTimes }} - </el-descriptions-item> - - <el-descriptions-item label="鏈�鍚庨�氱煡鏃堕棿"> - {{ formatDate(detailData.lastExecuteTime) }} - </el-descriptions-item> - <el-descriptions-item label="涓嬫閫氱煡鏃堕棿"> - {{ formatDate(detailData.nextNotifyTime) }} - </el-descriptions-item> - - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(detailData.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(detailData.updateTime) }} - </el-descriptions-item> - </el-descriptions> - - <!-- 鍒嗗壊绾� --> - <el-divider /> - - <el-descriptions :column="1" direction="vertical" border> - <el-descriptions-item label="鍥炶皟鏃ュ織"> - <el-table :data="detailData.logs"> - <el-table-column label="鏃ュ織缂栧彿" align="center" prop="id" /> - <el-table-column label="閫氱煡鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="閫氱煡娆℃暟" align="center" prop="notifyTimes" /> - <el-table-column label="閫氱煡鏃堕棿" align="center" prop="lastExecuteTime" width="180"> - <template #default="scope"> - <span>{{ formatDate(scope.row.createTime) }}</span> - </template> - </el-table-column> - <el-table-column label="鍝嶅簲缁撴灉" align="center" prop="response" /> - </el-table> - </el-descriptions-item> - </el-descriptions> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import * as PayNotifyApi from '@/api/pay/notify' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'PayNotifyDetail' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const detailLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const detailData = ref({}) - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - // 璁剧疆鏁版嵁 - detailLoading.value = true - try { - detailData.value = await PayNotifyApi.getNotifyTaskDetail(id) - } finally { - detailLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -</script> diff --git a/src/views/pay/notify/index.vue b/src/views/pay/notify/index.vue deleted file mode 100644 index 5daf754..0000000 --- a/src/views/pay/notify/index.vue +++ /dev/null @@ -1,224 +0,0 @@ -<template> - <doc-alert title="鏀粯鍔熻兘寮�鍚�" url="https://doc.iocoder.cn/pay/build/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="100px" - > - <el-form-item label="搴旂敤缂栧彿" prop="appId"> - <el-select - v-model="queryParams.appId" - placeholder="璇烽�夋嫨搴旂敤淇℃伅" - clearable - filterable - class="!w-240px" - > - <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> - </el-select> - </el-form-item> - <el-form-item label="閫氱煡绫诲瀷" prop="type"> - <el-select - v-model="queryParams.type" - placeholder="璇烽�夋嫨閫氱煡绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PAY_NOTIFY_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍏宠仈缂栧彿" prop="dataId"> - <el-input - v-model="queryParams.dataId" - placeholder="璇疯緭鍏ュ叧鑱旂紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="閫氱煡鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨閫氱煡鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PAY_NOTIFY_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗘埛璁㈠崟缂栧彿" prop="merchantOrderId"> - <el-input - v-model="queryParams.merchantOrderId" - placeholder="璇疯緭鍏ュ晢鎴疯鍗曠紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - style="width: 240px" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - range-separator="-" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="浠诲姟缂栧彿" align="center" prop="id" /> - <el-table-column label="搴旂敤缂栧彿" align="center" prop="appName" /> - <el-table-column label="鍟嗘埛璁㈠崟缂栧彿" align="center" prop="merchantOrderId" /> - <el-table-column label="閫氱煡绫诲瀷" align="center" prop="type"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column label="鍏宠仈缂栧彿" align="center" prop="dataId" /> - <el-table-column label="閫氱煡鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鏈�鍚庨�氱煡鏃堕棿" - align="center" - prop="lastExecuteTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column - label="涓嬫閫氱煡鏃堕棿" - align="center" - prop="nextNotifyTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="閫氱煡娆℃暟" align="center" prop="notifyTimes"> - <template #default="scope"> - <el-tag size="small" type="success"> - {{ scope.row.notifyTimes }} / {{ scope.row.maxNotifyTimes }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openDetail(scope.row.id)" - v-hasPermi="['pay:notify:query']" - > - 鏌ョ湅璇︽儏 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉缁勪欢 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氶瑙� --> - <NotifyDetail ref="detailRef" /> -</template> - -<script lang="ts" setup> -import * as PayNotifyApi from '@/api/pay/notify' -import * as PayAppApi from '@/api/pay/app' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import NotifyDetail from './NotifyDetail.vue' - -defineOptions({ name: 'PayNotify' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref() // 鍒楄〃鐨勬暟鎹� -const queryParams = ref({ - pageNo: 1, - pageSize: 10, - appId: null, - type: null, - dataId: null, - status: null, - merchantOrderId: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const appList = ref([]) // 鏀粯搴旂敤鍒楄〃闆嗗悎 -// 鏄惁鏄剧ず寮瑰嚭灞� -const open = ref(false) -// 閫氱煡璇︽儏 -const notifyDetail = ref<any>({ - logs: [] -}) - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.value.pageNo = 1 - getList() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await PayNotifyApi.getNotifyTaskPage(queryParams.value) - list.value = data.list - total.value = data.total - loading.value = false - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} - -/** 璇︽儏鎸夐挳鎿嶄綔 */ -const detailRef = ref() -const openDetail = (id: number) => { - detailRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - // 鑾峰緱绛涢�夐」 - appList.value = await PayAppApi.getAppList() -}) -</script> diff --git a/src/views/pay/order/OrderDetail.vue b/src/views/pay/order/OrderDetail.vue deleted file mode 100644 index 4f05c14..0000000 --- a/src/views/pay/order/OrderDetail.vue +++ /dev/null @@ -1,111 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="璁㈠崟璇︽儏" width="700px"> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="鍟嗘埛鍗曞彿"> - <el-tag size="small">{{ detailData.merchantOrderId }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="鏀粯鍗曞彿"> - <el-tag type="warning" size="small" v-if="detailData.no">{{ detailData.no }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="搴旂敤缂栧彿">{{ detailData.appId }}</el-descriptions-item> - <el-descriptions-item label="搴旂敤鍚嶇О">{{ detailData.appName }}</el-descriptions-item> - <el-descriptions-item label="鏀粯鐘舵��"> - <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="detailData.status" size="small" /> - </el-descriptions-item> - <el-descriptions-item label="鏀粯閲戦"> - <el-tag type="success" size="small">锟{ (detailData.price / 100.0).toFixed(2) }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="鎵嬬画璐�"> - <el-tag type="warning" size="small"> - 锟{ (detailData.channelFeePrice / 100.0).toFixed(2) }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="鎵嬬画璐规瘮渚�"> - {{ (detailData.channelFeeRate / 100.0).toFixed(2) }}% - </el-descriptions-item> - <el-descriptions-item label="鏀粯鏃堕棿"> - {{ formatDate(detailData.successTime) }} - </el-descriptions-item> - <el-descriptions-item label="澶辨晥鏃堕棿"> - {{ formatDate(detailData.expireTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(detailData.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(detailData.updateTime) }} - </el-descriptions-item> - </el-descriptions> - <!-- 鍒嗗壊绾� --> - <el-divider /> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="鍟嗗搧鏍囬">{{ detailData.subject }}</el-descriptions-item> - <el-descriptions-item label="鍟嗗搧鎻忚堪">{{ detailData.body }}</el-descriptions-item> - <el-descriptions-item label="鏀粯娓犻亾"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="detailData.channelCode" /> - </el-descriptions-item> - <el-descriptions-item label="鏀粯 IP">{{ detailData.userIp }}</el-descriptions-item> - <el-descriptions-item label="娓犻亾鍗曞彿"> - <el-tag size="mini" type="success" v-if="detailData.channelOrderNo"> - {{ detailData.channelOrderNo }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="娓犻亾鐢ㄦ埛">{{ detailData.channelUserId }}</el-descriptions-item> - <el-descriptions-item label="閫�娆鹃噾棰�"> - <el-tag size="mini" type="danger"> - 锟{ (detailData.refundPrice / 100.0).toFixed(2) }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="閫氱煡 URL">{{ detailData.notifyUrl }}</el-descriptions-item> - </el-descriptions> - <!-- 鍒嗗壊绾� --> - <el-divider /> - <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> - <el-descriptions-item label="鏀粯閫氶亾寮傛鍥炶皟鍐呭"> - <el-text>{{ detailData.extension.channelNotifyData }}</el-text> - </el-descriptions-item> - </el-descriptions> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import * as OrderApi from '@/api/pay/order' -import { formatDate } from '@/utils/formatTime' - -defineOptions({ name: 'PayOrderDetail' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const detailLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const detailData = ref({ - extension: {} -}) - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - // 璁剧疆鏁版嵁 - detailLoading.value = true - try { - detailData.value = await OrderApi.getOrderDetail(id) - if (!detailData.value.extension) { - detailData.value.extension = {} - } - } finally { - detailLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -</script> -<style> -.tag-purple { - color: #722ed1; - background: #f9f0ff; - border-color: #d3adf7; -} - -.tag-pink { - color: #eb2f96; - background: #fff0f6; - border-color: #ffadd2; -} -</style> diff --git a/src/views/pay/order/index.vue b/src/views/pay/order/index.vue deleted file mode 100644 index 1602659..0000000 --- a/src/views/pay/order/index.vue +++ /dev/null @@ -1,273 +0,0 @@ -<template> - <doc-alert title="鏀粯瀹濇敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/alipay-pay-demo/" /> - <doc-alert title="寰俊鍏紬鍙锋敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/wx-pub-pay-demo/" /> - <doc-alert title="寰俊灏忕▼搴忔敮浠樻帴鍏�" url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/" /> - - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="100px" - > - <el-form-item label="搴旂敤缂栧彿" prop="appId"> - <el-select - clearable - v-model="queryParams.appId" - placeholder="璇烽�夋嫨搴旂敤淇℃伅" - class="!w-240px" - > - <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> - </el-select> - </el-form-item> - <el-form-item label="鏀粯娓犻亾" prop="channelCode"> - <el-select - v-model="queryParams.channelCode" - placeholder="璇烽�夋嫨鏀粯娓犻亾" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗘埛鍗曞彿" prop="merchantOrderId"> - <el-input - v-model="queryParams.merchantOrderId" - placeholder="璇疯緭鍏ュ晢鎴峰崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鏀粯鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ユ敮浠樺崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娓犻亾鍗曞彿" prop="channelOrderNo"> - <el-input - v-model="queryParams.channelOrderNo" - placeholder="璇疯緭鍏ユ笭閬撳崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鏀粯鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨鏀粯鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PAY_ORDER_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['system:tenant:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" width="80" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏀粯閲戦" align="center" prop="price" width="100"> - <template #default="scope"> 锟{ parseFloat(scope.row.price / 100).toFixed(2) }} </template> - </el-table-column> - <el-table-column label="閫�娆鹃噾棰�" align="center" prop="refundPrice" width="100"> - <template #default="scope"> - 锟{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }} - </template> - </el-table-column> - <el-table-column label="鎵嬬画閲戦" align="center" prop="channelFeePrice" width="100"> - <template #default="scope"> - 锟{ parseFloat(scope.row.channelFeePrice / 100).toFixed(2) }} - </template> - </el-table-column> - <el-table-column label="璁㈠崟鍙�" align="left" width="300"> - <template #default="scope"> - <p class="order-font"> - <el-tag size="small"> 鍟嗘埛</el-tag> {{ scope.row.merchantOrderId }} - </p> - <p class="order-font" v-if="scope.row.no"> - <el-tag size="small" type="warning">鏀粯</el-tag> {{ scope.row.no }} - </p> - <p class="order-font" v-if="scope.row.channelOrderNo"> - <el-tag size="small" type="success">娓犻亾</el-tag> {{ scope.row.channelOrderNo }} - </p> - </template> - </el-table-column> - <el-table-column label="鏀粯鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="鏀粯娓犻亾" align="center" prop="channelCode" width="140"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" /> - </template> - </el-table-column> - <el-table-column - label="鏀粯鏃堕棿" - align="center" - prop="successTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏀粯搴旂敤" align="center" prop="appName" width="100" /> - <el-table-column label="鍟嗗搧鏍囬" align="center" prop="subject" width="180" /> - <el-table-column label="鎿嶄綔" align="center" fixed="right"> - <template #default="scope"> - <el-button - type="primary" - link - @click="openDetail(scope.row.id)" - v-hasPermi="['pay:order:query']" - > - 璇︽儏 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氶瑙� --> - <OrderDetail ref="detailRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as OrderApi from '@/api/pay/order' -import OrderDetail from './OrderDetail.vue' -import download from '@/utils/download' - -defineOptions({ name: 'PayOrder' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(false) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - appId: null, - channelCode: null, - merchantOrderId: null, - channelOrderNo: null, - no: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭绛夊緟 -const appList = ref([]) // 鏀粯搴旂敤鍒楄〃闆嗗悎 - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await OrderApi.getOrderPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await OrderApi.exportOrder(queryParams) - download.excel(data, '鏀粯璁㈠崟.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 棰勮璇︽儏 */ -const detailRef = ref() -const openDetail = (id: number) => { - detailRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() -}) -</script> -<style> -.order-font { - padding: 2px 0; - font-size: 12px; -} -</style> diff --git a/src/views/pay/refund/RefundDetail.vue b/src/views/pay/refund/RefundDetail.vue deleted file mode 100644 index 72f7a8c..0000000 --- a/src/views/pay/refund/RefundDetail.vue +++ /dev/null @@ -1,93 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="璇︽儏" width="700px"> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="鍟嗘埛閫�娆惧崟鍙�"> - <el-tag size="small">{{ refundDetail.merchantRefundId }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="娓犻亾閫�娆惧崟鍙�"> - <el-tag type="success" size="small" v-if="refundDetail.channelRefundNo">{{ - refundDetail.channelRefundNo - }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="鍟嗘埛鏀粯鍗曞彿"> - <el-tag size="small">{{ refundDetail.merchantOrderId }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="娓犻亾鏀粯鍗曞彿"> - <el-tag type="success" size="small">{{ refundDetail.channelOrderNo }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="搴旂敤缂栧彿">{{ refundDetail.appId }}</el-descriptions-item> - <el-descriptions-item label="搴旂敤鍚嶇О">{{ refundDetail.appName }}</el-descriptions-item> - <el-descriptions-item label="鏀粯閲戦"> - <el-tag type="success" size="small"> - 锟{ (refundDetail.payPrice / 100.0).toFixed(2) }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="閫�娆鹃噾棰�"> - <el-tag size="mini" type="danger"> - 锟{ (refundDetail.refundPrice / 100.0).toFixed(2) }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="閫�娆剧姸鎬�"> - <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="refundDetail.status" /> - </el-descriptions-item> - <el-descriptions-item label="閫�娆炬椂闂�"> - {{ formatDate(refundDetail.successTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(refundDetail.createTime) }} - </el-descriptions-item> - <el-descriptions-item label="鏇存柊鏃堕棿"> - {{ formatDate(refundDetail.updateTime) }} - </el-descriptions-item> - </el-descriptions> - <!-- 鍒嗗壊绾� --> - <el-divider /> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="閫�娆炬笭閬�"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="refundDetail.channelCode" /> - </el-descriptions-item> - <el-descriptions-item label="閫�娆惧師鍥�">{{ refundDetail.reason }}</el-descriptions-item> - <el-descriptions-item label="閫�娆� IP">{{ refundDetail.userIp }}</el-descriptions-item> - <el-descriptions-item label="閫氱煡 URL">{{ refundDetail.notifyUrl }}</el-descriptions-item> - </el-descriptions> - <!-- 鍒嗗壊绾� --> - <el-divider /> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="娓犻亾閿欒鐮�"> - {{ refundDetail.channelErrorCode }} - </el-descriptions-item> - <el-descriptions-item label="娓犻亾閿欒鐮佹弿杩�"> - {{ refundDetail.channelErrorMsg }} - </el-descriptions-item> - </el-descriptions> - <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> - <el-descriptions-item label="鏀粯閫氶亾寮傛鍥炶皟鍐呭"> - {{ refundDetail.channelNotifyData }} - </el-descriptions-item> - </el-descriptions> - </Dialog> -</template> -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import { formatDate } from '@/utils/formatTime' -import * as RefundApi from '@/api/pay/refund' - -defineOptions({ name: 'PayRefundDetail' }) - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const detailLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const refundDetail = ref({}) - -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - // 璁剧疆鏁版嵁 - detailLoading.value = true - try { - refundDetail.value = await RefundApi.getRefund(id) - } finally { - detailLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -</script> diff --git a/src/views/pay/refund/index.vue b/src/views/pay/refund/index.vue deleted file mode 100644 index eaa17b4..0000000 --- a/src/views/pay/refund/index.vue +++ /dev/null @@ -1,298 +0,0 @@ -<template> - <doc-alert title="鏀粯瀹濄�佸井淇¢��娆炬帴鍏�" url="https://doc.iocoder.cn/pay/refund-demo/" /> - - <!-- 鎼滅储宸ヤ綔鏍� --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="120px" - > - <el-form-item label="搴旂敤缂栧彿" prop="appId"> - <el-select - v-model="queryParams.appId" - clearable - placeholder="璇烽�夋嫨搴旂敤淇℃伅" - class="!w-240px" - > - <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> - </el-select> - </el-form-item> - <el-form-item label="閫�娆炬笭閬�" prop="channelCode"> - <el-select - v-model="queryParams.channelCode" - placeholder="璇烽�夋嫨閫�娆炬笭閬�" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗘埛鏀粯鍗曞彿" prop="merchantOrderId"> - <el-input - v-model="queryParams.merchantOrderId" - placeholder="璇疯緭鍏ュ晢鎴锋敮浠樺崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍟嗘埛閫�娆惧崟鍙�" prop="merchantRefundId"> - <el-input - v-model="queryParams.merchantRefundId" - placeholder="璇疯緭鍏ュ晢鎴烽��娆惧崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娓犻亾鏀粯鍗曞彿" prop="channelOrderNo"> - <el-input - v-model="queryParams.channelOrderNo" - placeholder="璇疯緭鍏ユ笭閬撴敮浠樺崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娓犻亾閫�娆惧崟鍙�" prop="channelRefundNo"> - <el-input - v-model="queryParams.channelRefundNo" - placeholder="璇疯緭鍏ユ笭閬撻��娆惧崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="閫�娆剧姸鎬�" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨閫�娆剧姸鎬�" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.PAY_REFUND_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" /> 鎼滅储 </el-button> - <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆 </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['system:tenant:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 瀵煎嚭 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏀粯閲戦" align="center" prop="payPrice" width="100"> - <template #default="scope"> - 锟{ parseFloat(scope.row.payPrice / 100).toFixed(2) }} - </template> - </el-table-column> - <el-table-column label="閫�娆鹃噾棰�" align="center" prop="refundPrice" width="100"> - <template #default="scope"> - 锟{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }} - </template> - </el-table-column> - <el-table-column label="閫�娆捐鍗曞彿" align="left" width="300"> - <template #default="scope"> - <p class="order-font"> - <el-tag size="small">鍟嗘埛</el-tag> {{ scope.row.merchantRefundId }} - </p> - <p class="order-font"> - <el-tag size="small" type="warning">閫�娆�</el-tag> {{ scope.row.no }} - </p> - <p class="order-font" v-if="scope.row.channelRefundNo"> - <el-tag size="small" type="success">娓犻亾</el-tag> {{ scope.row.channelRefundNo }} - </p> - </template> - </el-table-column> - <el-table-column label="鏀粯璁㈠崟鍙�" align="left" width="300"> - <template #default="scope"> - <p class="order-font"> - <el-tag size="small">鍟嗘埛</el-tag> {{ scope.row.merchantOrderId }} - </p> - <p class="order-font"> - <el-tag size="small" type="success">娓犻亾</el-tag> {{ scope.row.channelOrderNo }} - </p> - </template> - </el-table-column> - <el-table-column label="閫�娆剧姸鎬�" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="閫�娆炬笭閬�" align="center" width="140"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" /> - </template> - </el-table-column> - <el-table-column - label="鎴愬姛鏃堕棿" - align="center" - prop="successTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="鏀粯搴旂敤" align="center" prop="successTime" width="100"> - <template #default="scope"> - <span>{{ scope.row.appName }}</span> - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" align="center" fixed="right"> - <template #default="scope"> - <el-button - type="primary" - link - @click="openDetail(scope.row.id)" - v-hasPermi="['pay:order:query']" - > - 璇︽儏 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氶瑙� --> - <RefundDetail ref="detailRef" @success="getList" /> -</template> -<script lang="ts" setup> -import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import * as RefundApi from '@/api/pay/refund' -import * as AppApi from '@/api/pay/app' -import RefundDetail from './RefundDetail.vue' -import download from '@/utils/download' - -defineOptions({ name: 'PayRefund' }) - -const message = useMessage() // 娑堟伅寮圭獥 - -const loading = ref(false) // 鍒楄〃閬僵灞� -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - merchantId: undefined, - appId: undefined, - channelCode: undefined, - merchantOrderId: undefined, - merchantRefundId: undefined, - status: undefined, - payPrice: undefined, - refundPrice: undefined, - channelOrderNo: undefined, - channelRefundNo: undefined, - createTime: [], - successTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭绛夊緟 -const appList = ref([]) // 鏀粯搴旂敤鍒楄〃闆嗗悎 - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await RefundApi.getRefundPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value?.resetFields() - handleQuery() -} - -/** 瀵煎嚭鎸夐挳鎿嶄綔 */ -const handleExport = async () => { - try { - // 瀵煎嚭鐨勪簩娆$‘璁� - await message.exportConfirm() - // 鍙戣捣瀵煎嚭 - exportLoading.value = true - const data = await RefundApi.exportRefund(queryParams) - download.excel(data, '鏀粯璁㈠崟.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 棰勮璇︽儏 */ -const detailRef = ref() -const openDetail = (id: number) => { - detailRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(async () => { - await getList() - appList.value = await AppApi.getAppList() -}) -</script> -<style> -.order-font { - padding: 2px 0; - font-size: 12px; -} -</style> diff --git a/src/views/pay/transfer/CreatePayTransfer.vue b/src/views/pay/transfer/CreatePayTransfer.vue deleted file mode 100644 index 3170650..0000000 --- a/src/views/pay/transfer/CreatePayTransfer.vue +++ /dev/null @@ -1,135 +0,0 @@ -<template> - <Dialog title="鍙戣捣杞处" v-model="dialogVisible" width="800px"> - <el-card style="margin-top: 10px"> - <el-descriptions title="杞处淇℃伅" :column="2" border> - <el-descriptions-item label="杞处绫诲瀷"> - {{ typeName }} - </el-descriptions-item> - <el-descriptions-item label="杞处閲戦(鍏�)"> - 锟{ (transfer.price / 100.0).toFixed(2) }} - </el-descriptions-item> - <el-descriptions-item label="鏀舵浜哄鍚�"> - {{ transfer.userName }} - </el-descriptions-item> - <el-descriptions-item label="鏀粯瀹濈櫥褰曡处鍙�" v-if="transfer.type === 1"> - {{ transfer.alipayLogonId }} - </el-descriptions-item> - <el-descriptions-item label="寰俊 openid" v-if="transfer.type === 2"> - {{ transfer.openid }} - </el-descriptions-item> - </el-descriptions> - </el-card> - <el-card style="margin-top: 20px"> - <template #header> - <div class="card-header"> - <span>閫夋嫨杞处娓犻亾</span> - </div> - </template> - <div> - <el-radio-group v-model="channelCode"> - <el-radio - label="alipay_pc" - :disabled="transfer.type === 2 || transfer.type === 3 || transfer.type === 4" - > - <img :src="svg_alipay_app" /> - </el-radio> - <el-radio - label="wx_app" - :disabled="transfer.type === 1 || transfer.type === 3 || transfer.type === 4" - > - <img :src="svg_wx_app" /> - </el-radio> - </el-radio-group> - </div> - </el-card> - <el-divider /> - <div style="text-align: right"> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </div> - </Dialog> -</template> - -<script lang="ts" setup> -import * as PayTransferApi from '@/api/pay/transfer' -import { computed, PropType } from 'vue' -import { DICT_TYPE, getDictLabel } from '@/utils/dict' -// 瀵煎叆鍥炬爣 -import svg_alipay_app from '@/assets/svgs/pay/icon/alipay_app.svg' -import svg_wx_app from '@/assets/svgs/pay/icon/wx_app.svg' -import { yuanToFen } from '@/utils' -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 -const formLoading = ref(false) // 鎻愪氦鐨勬寜閽鐢� -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -defineOptions({ name: 'CreatePayTransfer' }) - -// 鎻愪氦鏁版嵁 -let submitTransferData: PayTransferApi.TransferVO - -const transfer = reactive({ - appId: undefined, - channelCode: undefined, - merchantTransferId: undefined, - type: undefined, - price: undefined, - subject: undefined, - userName: undefined, - alipayLogonId: undefined, - openid: undefined -}) -const dialogVisible = ref(false) -const typeName = computed(() => { - return getDictLabel(DICT_TYPE.PAY_TRANSFER_TYPE, transfer.type) -}) -const channelCode = computed(() => { - let channelCode = 'alipay_pc' - if (transfer.type === 2) { - channelCode = 'wx_app' - } - // TODO 閾惰鍗″拰閽卞寘 杞处寰呭疄鐜� - return channelCode -}) - -/** 鎵撳紑寮圭獥 */ -const showPayTransfer = async (payTransfer: PayTransferApi.TransferVO) => { - dialogVisible.value = true - submitTransferData = payTransfer - transfer.merchantTransferId = payTransfer.merchantTransferId - transfer.price = payTransfer.price - transfer.userName = payTransfer.userName - transfer.type = payTransfer.type - transfer.appId = payTransfer.appId - transfer.subject = payTransfer.subject - transfer.alipayLogonId = payTransfer.alipayLogonId - transfer.openid = payTransfer.openid -} -/** 鍏抽棴寮圭獥 */ -const close = async () => { - dialogVisible.value = false -} -defineExpose({ showPayTransfer, close }) // 鎻愪緵 showPayTransfer锛� close 鏂规硶锛岀敤浜庢墦寮�, 鍏抽棴寮圭獥 - -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - formLoading.value = true - try { - submitTransferData.channelCode = channelCode.value - await PayTransferApi.createTransfer(submitTransferData) - message.success('鍙戣捣杞处鎴愬姛. 鏄惁杞处鎴愬姛,浠ヨ浆璐﹁鍗曠姸鎬佷负鍑�') - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - dialogVisible.value = false - } finally { - formLoading.value = false - } -} -</script> - -<style lang="scss" scoped> -.card-header { - display: flex; - justify-content: space-between; - align-items: center; -} -</style> diff --git a/src/views/pay/transfer/TransferDetail.vue b/src/views/pay/transfer/TransferDetail.vue deleted file mode 100644 index ad769d2..0000000 --- a/src/views/pay/transfer/TransferDetail.vue +++ /dev/null @@ -1,80 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" title="杞处鍗曡鎯�" width="700px"> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="鍟嗘埛鍗曞彿"> - <el-tag size="small">{{ detailData.merchantTransferId }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="杞处鍗曞彿"> - <el-tag type="warning" size="small" v-if="detailData.no">{{ detailData.no }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="搴旂敤缂栧彿">{{ detailData.appId }}</el-descriptions-item> - <el-descriptions-item label="杞处鐘舵��"> - <dict-tag :type="DICT_TYPE.PAY_TRANSFER_STATUS" :value="detailData.status" size="small" /> - </el-descriptions-item> - <el-descriptions-item label="杞处閲戦"> - <el-tag type="success" size="small">锟{ (detailData.price / 100.0).toFixed(2) }}</el-tag> - </el-descriptions-item> - <el-descriptions-item label="杞处鏃堕棿"> - {{ formatDate(detailData.successTime) }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ formatDate(detailData.createTime) }} - </el-descriptions-item> - </el-descriptions> - <!-- 鍒嗗壊绾� --> - <el-divider /> - <el-descriptions :column="2" label-class-name="desc-label"> - <el-descriptions-item label="鏀舵浜哄鍚�">{{ detailData.userName }}</el-descriptions-item> - <el-descriptions-item label="鏀粯瀹濈櫥褰曡处鍙�" v-if="detailData.type === 1"> - {{ detailData.alipayLogonId }} - </el-descriptions-item> - <el-descriptions-item label="寰俊 openid" v-if="detailData.type === 2"> - {{ detailData.openid }} - </el-descriptions-item> - <el-descriptions-item label="鏀粯娓犻亾"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="detailData.channelCode" /> - </el-descriptions-item> - <el-descriptions-item label="鏀粯 IP">{{ detailData.userIp }}</el-descriptions-item> - <el-descriptions-item label="娓犻亾鍗曞彿"> - <el-tag size="mini" type="success" v-if="detailData.channelTransferNo"> - {{ detailData.channelTransferNo }} - </el-tag> - </el-descriptions-item> - <el-descriptions-item label="閫氱煡 URL">{{ detailData.notifyUrl }}</el-descriptions-item> - </el-descriptions> - <el-divider /> - <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> - <el-descriptions-item label="杞处娓犻亾閫氱煡鍐呭"> - <el-text>{{ detailData.channelNotifyData }}</el-text> - </el-descriptions-item> - </el-descriptions> - <el-divider /> - <div style="text-align: right"> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </div> - </Dialog> -</template> - -<script lang="ts" setup> -import { DICT_TYPE } from '@/utils/dict' -import * as TransferApi from '@/api/pay/transfer' -import { formatDate } from '@/utils/formatTime' -defineOptions({ name: 'PayTransferDetail' }) -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const detailLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑 -const detailData = ref({}) -/** 鎵撳紑寮圭獥 */ -const open = async (id: number) => { - dialogVisible.value = true - // 璁剧疆鏁版嵁 - detailLoading.value = true - try { - detailData.value = await TransferApi.getTransfer(id) - } finally { - detailLoading.value = false - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -</script> - -<style scoped></style> diff --git a/src/views/pay/transfer/index.vue b/src/views/pay/transfer/index.vue deleted file mode 100644 index b901f34..0000000 --- a/src/views/pay/transfer/index.vue +++ /dev/null @@ -1,267 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="100px" - > - <el-form-item label="杞处鍗曞彿" prop="no"> - <el-input - v-model="queryParams.no" - placeholder="璇疯緭鍏ヨ浆璐﹀崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="杞处娓犻亾" prop="channelCode"> - <el-select - v-model="queryParams.channelCode" - placeholder="璇烽�夋嫨鏀粯娓犻亾" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍟嗘埛鍗曞彿" prop="merchantTransferId"> - <el-input - v-model="queryParams.merchantTransferId" - placeholder="璇疯緭鍏ュ晢鎴峰崟鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="绫诲瀷" prop="type"> - <el-select v-model="queryParams.type" placeholder="璇烽�夋嫨绫诲瀷" clearable class="!w-240px"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_TRANSFER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="杞处鐘舵��" prop="status"> - <el-select - v-model="queryParams.status" - placeholder="璇烽�夋嫨杞处鐘舵��" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.PAY_TRANSFER_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - - <el-form-item label="鏀舵浜哄鍚�" prop="userName"> - <el-input - v-model="queryParams.userName" - placeholder="璇疯緭鍏ユ敹娆句汉濮撳悕" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="娓犻亾鍗曞彿" prop="channelTransferNo"> - <el-input - v-model="queryParams.channelTransferNo" - placeholder="娓犻亾鍗曞彿" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="搴旂敤缂栧彿" align="center" prop="appId" /> - <el-table-column label="绫诲瀷" align="center" prop="type" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_TRANSFER_TYPE" :value="scope.row.type" /> - </template> - </el-table-column> - <el-table-column label="杞处閲戦" align="center" prop="price"> - <template #default="scope"> - <span>锟{ (scope.row.price / 100.0).toFixed(2) }}</span> - </template> - </el-table-column> - <el-table-column label="杞处鐘舵��" align="center" prop="status" width="120"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_TRANSFER_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column label="璁㈠崟鍙�" align="left" width="300"> - <template #default="scope"> - <p class="transfer-font"> - <el-tag size="small"> 鍟嗘埛</el-tag> - {{ scope.row.merchantTransferId }} - </p> - <p class="transfer-font" v-if="scope.row.no"> - <el-tag size="small" type="warning">杞处</el-tag> - {{ scope.row.no }} - </p> - <p class="transfer-font" v-if="scope.row.channelTransferNo"> - <el-tag size="small" type="success">娓犻亾</el-tag> - {{ scope.row.channelTransferNo }} - </p> - </template> - </el-table-column> - <el-table-column label="鏀舵浜哄鍚�" align="center" prop="userName" width="120" /> - <el-table-column label="鏀舵璐﹀彿" align="left" width="200"> - <template #default="scope"> - <p class="transfer-font" v-if="scope.row.alipayLogonId"> - <el-tag size="small">鏀粯瀹濈櫥褰曞彿</el-tag> - {{ scope.row.alipayLogonId }} - </p> - <p class="transfer-font" v-if="scope.row.openid"> - <el-tag size="small">寰俊 openId</el-tag> - {{ scope.row.openid }} - </p> - </template> - </el-table-column> - <el-table-column label="杞处鏍囬" align="center" prop="subject" width="120" /> - <el-table-column label="杞处娓犻亾" align="center" prop="channelCode"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" /> - </template> - </el-table-column> - <el-table-column - label="杞处鎴愬姛鏃堕棿" - align="center" - prop="successTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center" fixed="right"> - <template #default="scope"> - <el-button link type="primary" @click="openDetail(scope.row.id)"> 璇︽儏 </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - <TransferDetail ref="detailRef" /> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import * as TransferApi from '@/api/pay/transfer' -import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' -import TransferDetail from './TransferDetail.vue' -defineOptions({ name: 'PayTransfer' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - no: null, - appId: null, - channelId: null, - channelCode: null, - merchantTransferId: null, - type: null, - status: null, - successTime: [], - price: null, - subject: null, - userName: null, - alipayLogonId: null, - openid: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� -const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑 - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await TransferApi.getTransferPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const detailRef = ref() -const openDetail = (id: number) => { - detailRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> - -<style scoped> -.transfer-font { - padding: 2px 0; - font-size: 12px; -} -</style> diff --git a/src/views/pay/wallet/balance/WalletForm.vue b/src/views/pay/wallet/balance/WalletForm.vue deleted file mode 100644 index 8173e12..0000000 --- a/src/views/pay/wallet/balance/WalletForm.vue +++ /dev/null @@ -1,22 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="800"> - <WalletTransactionList :wallet-id="walletId" /> - <template #footer> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import WalletTransactionList from '../transaction/WalletTransactionList.vue' -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const walletId = ref(0) -/** 鎵撳紑寮圭獥 */ -const open = async (theWalletId: number) => { - dialogVisible.value = true - dialogTitle.value = '閽卞寘浣欓鏄庣粏' - walletId.value = theWalletId -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 -</script> diff --git a/src/views/pay/wallet/balance/index.vue b/src/views/pay/wallet/balance/index.vue deleted file mode 100644 index 1a37eec..0000000 --- a/src/views/pay/wallet/balance/index.vue +++ /dev/null @@ -1,156 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="鐢ㄦ埛缂栧彿" prop="userId"> - <el-input - v-model="queryParams.userId" - placeholder="璇疯緭鍏ョ敤鎴风紪鍙�" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐢ㄦ埛绫诲瀷" prop="userType"> - <el-select - v-model="queryParams.userType" - placeholder="璇烽�夋嫨鐢ㄦ埛绫诲瀷" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.USER_TYPE)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="userId" /> - <el-table-column label="鐢ㄦ埛绫诲瀷" align="center" prop="userType"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" /> - </template> - </el-table-column> - <el-table-column label="浣欓" align="center" prop="balance"> - <template #default="{ row }"> {{ fenToYuan(row.balance) }} 鍏�</template> - </el-table-column> - <el-table-column label="绱鏀嚭" align="center" prop="totalExpense"> - <template #default="{ row }"> {{ fenToYuan(row.totalExpense) }} 鍏�</template> - </el-table-column> - <el-table-column label="绱鍏呭��" align="center" prop="totalRecharge"> - <template #default="{ row }"> {{ fenToYuan(row.totalRecharge) }} 鍏�</template> - </el-table-column> - <el-table-column label="鍐荤粨閲戦" align="center" prop="freezePrice"> - <template #default="{ row }"> {{ fenToYuan(row.freezePrice) }} 鍏�</template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button link type="primary" @click="openForm(scope.row.id)">璇︽儏</el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 寮圭獥 --> - <WalletForm ref="formRef" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { fenToYuan } from '@/utils' -import * as WalletApi from '@/api/pay/wallet/balance' -import WalletForm from './WalletForm.vue' - -defineOptions({ name: 'WalletBalance' }) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - userId: null, - userType: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await WalletApi.getWalletPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (id?: number) => { - formRef.value.open(id) -} - -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/pay/wallet/rechargePackage/WalletRechargePackageForm.vue b/src/views/pay/wallet/rechargePackage/WalletRechargePackageForm.vue deleted file mode 100644 index 0153225..0000000 --- a/src/views/pay/wallet/rechargePackage/WalletRechargePackageForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="150px" - v-loading="formLoading" - > - <el-form-item label="濂楅鍚�" prop="name"> - <el-input v-model="formData.name" placeholder="璇疯緭鍏ュ椁愬悕" /> - </el-form-item> - <el-form-item label="鏀粯閲戦(鍏�)" prop="payPrice"> - <el-input-number v-model="formData.payPrice" :min="0" :precision="2" :step="0.01" /> - </el-form-item> - <el-form-item label="璧犻�侀噾棰�(鍏�)" prop="bonusPrice"> - <el-input-number v-model="formData.bonusPrice" :min="0" :precision="2" :step="0.01" /> - </el-form-item> - <el-form-item label="寮�鍚姸鎬�" prop="status"> - <el-radio-group v-model="formData.status"> - <el-radio - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">纭� 瀹�</el-button> - <el-button @click="dialogVisible = false">鍙� 娑�</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as WalletRechargePackageApi from '@/api/pay/wallet/rechargePackage' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { fenToYuan, yuanToFen } from '@/utils' -const { t } = useI18n() // 鍥介檯鍖� -const message = useMessage() // 娑堟伅寮圭獥 - -const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀� -const dialogTitle = ref('') // 寮圭獥鐨勬爣棰� -const formLoading = ref(false) // 琛ㄥ崟鐨勫姞杞戒腑锛�1锛変慨鏀规椂鐨勬暟鎹姞杞斤紱2锛夋彁浜ょ殑鎸夐挳绂佺敤 -const formType = ref('') // 琛ㄥ崟鐨勭被鍨嬶細create - 鏂板锛泆pdate - 淇敼 -const formData = ref({ - id: undefined, - name: undefined, - payPrice: undefined, - bonusPrice: undefined, - status: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '濂楅鍚嶄笉鑳戒负绌�', trigger: 'blur' }], - payPrice: [{ required: true, message: '鏀粯閲戦涓嶈兘涓虹┖', trigger: 'blur' }], - bonusPrice: [{ required: true, message: '璧犻�侀噾棰濅笉鑳戒负绌�', trigger: 'blur' }], - status: [{ required: true, message: '鐘舵�佷笉鑳戒负绌�', trigger: 'blur' }] -}) -const formRef = ref() // 琛ㄥ崟 Ref - -/** 鎵撳紑寮圭獥 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 淇敼鏃讹紝璁剧疆鏁版嵁 - if (id) { - formLoading.value = true - try { - formData.value = await WalletRechargePackageApi.getWalletRechargePackage(id) - formData.value.payPrice = fenToYuan(formData.value.payPrice) - formData.value.bonusPrice = fenToYuan(formData.value.bonusPrice) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥 - -/** 鎻愪氦琛ㄥ崟 */ -const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋� -const submitForm = async () => { - // 鏍¢獙琛ㄥ崟 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 鎻愪氦璇锋眰 - formLoading.value = true - try { - const data = { ...formData.value } - data.payPrice = yuanToFen(data.payPrice) - data.bonusPrice = yuanToFen(data.bonusPrice) - if (formType.value === 'create') { - await WalletRechargePackageApi.createWalletRechargePackage(data) - message.success(t('common.createSuccess')) - } else { - await WalletRechargePackageApi.updateWalletRechargePackage(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 鍙戦�佹搷浣滄垚鍔熺殑浜嬩欢 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 閲嶇疆琛ㄥ崟 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - payPrice: undefined, - bonusPrice: undefined, - status: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/pay/wallet/rechargePackage/index.vue b/src/views/pay/wallet/rechargePackage/index.vue deleted file mode 100644 index f097577..0000000 --- a/src/views/pay/wallet/rechargePackage/index.vue +++ /dev/null @@ -1,185 +0,0 @@ -<template> - <ContentWrap> - <!-- 鎼滅储宸ヤ綔鏍� --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="濂楅鍚�" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="璇疯緭鍏ュ椁愬悕" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="鐘舵��" prop="status"> - <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable class="!w-240px"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="鍒涘缓鏃堕棿" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="寮�濮嬫棩鏈�" - end-placeholder="缁撴潫鏃ユ湡" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 鎼滅储</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 閲嶇疆</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['pay:wallet-recharge-package:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 鏂板 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 鍒楄〃 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="濂楅鍚�" align="center" prop="name" /> - <el-table-column label="鏀粯閲戦" align="center" prop="payPrice"> - <template #default="{ row }"> {{ fenToYuan(row.payPrice) }} 鍏�</template> - </el-table-column> - <el-table-column label="璧犻�侀噾棰�" align="center" prop="bonusPrice"> - <template #default="{ row }"> {{ fenToYuan(row.bonusPrice) }} 鍏�</template> - </el-table-column> - <el-table-column label="鐘舵��" align="center" prop="status"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> - </template> - </el-table-column> - <el-table-column - label="鍒涘缓鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="鎿嶄綔" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['pay:wallet-recharge-package:update']" - > - 缂栬緫 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['pay:wallet-recharge-package:delete']" - > - 鍒犻櫎 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 琛ㄥ崟寮圭獥锛氭坊鍔�/淇敼 --> - <WalletRechargePackageForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { dateFormatter } from '@/utils/formatTime' -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import * as WalletRechargePackageApi from '@/api/pay/wallet/rechargePackage' -import WalletRechargePackageForm from './WalletRechargePackageForm.vue' -import { fenToYuan } from '@/utils' - -defineOptions({ name: 'WalletRechargePackage' }) - -const message = useMessage() // 娑堟伅寮圭獥 -const { t } = useI18n() // 鍥介檯鍖� - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - payPrice: null, - bonusPrice: null, - status: null, - createTime: [] -}) -const queryFormRef = ref() // 鎼滅储鐨勮〃鍗� - -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - const data = await WalletRechargePackageApi.getWalletRechargePackagePage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 鎼滅储鎸夐挳鎿嶄綔 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 閲嶇疆鎸夐挳鎿嶄綔 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 娣诲姞/淇敼鎿嶄綔 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 鍒犻櫎鎸夐挳鎿嶄綔 */ -const handleDelete = async (id: number) => { - try { - // 鍒犻櫎鐨勪簩娆$‘璁� - await message.delConfirm() - // 鍙戣捣鍒犻櫎 - await WalletRechargePackageApi.deleteWalletRechargePackage(id) - message.success(t('common.delSuccess')) - // 鍒锋柊鍒楄〃 - await getList() - } catch {} -} -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/pay/wallet/transaction/WalletTransactionList.vue b/src/views/pay/wallet/transaction/WalletTransactionList.vue deleted file mode 100644 index c440778..0000000 --- a/src/views/pay/wallet/transaction/WalletTransactionList.vue +++ /dev/null @@ -1,68 +0,0 @@ -<template> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="缂栧彿" align="center" prop="id" /> - <el-table-column label="閽卞寘缂栧彿" align="center" prop="walletId" /> - <el-table-column label="鍏宠仈涓氬姟鏍囬" align="center" prop="title" /> - <el-table-column label="浜ゆ槗閲戦" align="center" prop="price"> - <template #default="{ row }"> {{ fenToYuan(row.price) }} 鍏�</template> - </el-table-column> - <el-table-column label="閽卞寘浣欓" align="center" prop="balance"> - <template #default="{ row }"> {{ fenToYuan(row.balance) }} 鍏�</template> - </el-table-column> - <el-table-column - label="浜ゆ槗鏃堕棿" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - </el-table> - <!-- 鍒嗛〉 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> -</template> - -<script lang="ts" setup> -import { dateFormatter } from '@/utils/formatTime' -import * as WalletTransactionApi from '@/api/pay/wallet/transaction' -import { fenToYuan } from '@/utils' -defineOptions({ name: 'WalletTransactionList' }) -const { walletId }: { walletId: number } = defineProps({ - walletId: { - type: Number, - required: false - } -}) - -const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑 -const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁� -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - walletId: null -}) -const list = ref([]) // 鍒楄〃鐨勬暟鎹� -/** 鏌ヨ鍒楄〃 */ -const getList = async () => { - loading.value = true - try { - queryParams.walletId = walletId - const data = await WalletTransactionApi.getWalletTransactionPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} -/** 鍒濆鍖� **/ -onMounted(() => { - getList() -}) -</script> -<style scoped lang="scss"></style> -- Gitblit v1.9.3