diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d3f0aa8..34310929 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -102,6 +102,7 @@ "codemirror", "commitlint", "cropperjs", + "echart", "echarts", "esnext", "esno", @@ -116,10 +117,12 @@ "sider", "sortablejs", "stylelint", + "svgs", "unocss", "unplugin", "unref", "videojs", + "VITE", "vitejs", "vueuse", "wangeditor", diff --git a/package.json b/package.json index 21a731a8..fb0f23ad 100644 --- a/package.json +++ b/package.json @@ -36,20 +36,20 @@ "@wangeditor/editor-for-vue": "^5.1.10", "@zxcvbn-ts/core": "^3.0.4", "animate.css": "^4.1.1", - "axios": "^1.5.1", + "axios": "^1.6.0", "benz-amr-recorder": "^1.1.5", "bpmn-js-token-simulation": "^0.10.0", "camunda-bpmn-moddle": "^7.0.1", "cropperjs": "^1.6.1", "crypto-js": "^4.2.0", "dayjs": "^1.11.10", - "diagram-js": "^12.5.0", + "diagram-js": "^12.6.0", + "driver.js": "^1.3.0", "echarts": "^5.4.3", "echarts-wordcloud": "^2.1.0", "element-plus": "2.4.1", "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", - "intro.js": "^7.2.0", "jsencrypt": "^3.3.2", "lodash-es": "^4.17.21", "min-dash": "^4.1.1", @@ -64,7 +64,7 @@ "video.js": "^7.21.5", "vue": "^3.3.7", "vue-dompurify-html": "^4.1.4", - "vue-i18n": "^9.5.0", + "vue-i18n": "^9.6.2", "vue-router": "^4.2.5", "vue-types": "^5.1.1", "vuedraggable": "^4.1.0", @@ -72,20 +72,19 @@ "xml-js": "^1.6.11" }, "devDependencies": { - "@commitlint/cli": "^18.0.0", - "@commitlint/config-conventional": "^18.0.0", - "@iconify/json": "^2.2.132", + "@commitlint/cli": "^18.2.0", + "@commitlint/config-conventional": "^18.1.0", + "@iconify/json": "^2.2.135", "@intlify/unplugin-vue-i18n": "^1.4.0", "@purge-icons/generated": "^0.9.0", - "@types/intro.js": "^5.1.3", "@types/lodash-es": "^4.17.10", - "@types/node": "^20.8.8", + "@types/node": "^20.8.9", "@types/nprogress": "^0.2.2", "@types/qrcode": "^1.5.4", "@types/qs": "^6.9.9", "@types/sortablejs": "^1.15.4", - "@typescript-eslint/eslint-plugin": "^6.9.0", - "@typescript-eslint/parser": "^6.9.0", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", "@unocss/transformer-variant-group": "^0.57.1", "@unocss/eslint-config": "^0.57.1", "@vitejs/plugin-legacy": "^4.1.1", @@ -99,24 +98,24 @@ "eslint-config-prettier": "^9.0.0", "eslint-define-config": "^1.24.1", "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-vue": "^9.18.0", + "eslint-plugin-vue": "^9.18.1", "lint-staged": "^15.0.2", "postcss": "^8.4.31", "postcss-html": "^1.5.0", "postcss-scss": "^4.0.9", "prettier": "^3.0.3", "rimraf": "^5.0.5", - "rollup": "^4.1.4", - "sass": "^1.69.4", + "rollup": "^4.1.5", + "sass": "^1.69.5", "stylelint": "^15.11.0", "stylelint-config-html": "^1.1.0", "stylelint-config-recommended": "^13.0.0", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", - "terser": "^5.22.0", + "terser": "^5.23.0", "typescript": "5.2.2", "unocss": "^0.57.1", - "unplugin-auto-import": "^0.16.6", + "unplugin-auto-import": "^0.16.7", "unplugin-element-plus": "^0.8.0", "unplugin-vue-components": "^0.25.2", "vite": "4.5.0", @@ -128,7 +127,7 @@ "vite-plugin-svg-icons": "^2.0.1", "vite-plugin-top-level-await": "^1.3.1", "vue-eslint-parser": "^9.3.2", - "vue-tsc": "^1.8.20" + "vue-tsc": "^1.8.22" }, "license": "MIT", "repository": { diff --git a/src/api/crm/product/index.ts b/src/api/crm/product/index.ts new file mode 100644 index 00000000..cb1ddcda --- /dev/null +++ b/src/api/crm/product/index.ts @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +export interface ProductVO { + id: number + name: string + no: string + unit: string + price: number + status: number + categoryId: number + description: string + ownerUserId: number +} + +// 查询产品列表 +export const getProductPage = async (params) => { + return await request.get({ url: `/crm/product/page`, params }) +} + +// 查询产品详情 +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/productCategory/index.ts b/src/api/crm/productCategory/index.ts new file mode 100644 index 00000000..6341d1bc --- /dev/null +++ b/src/api/crm/productCategory/index.ts @@ -0,0 +1,33 @@ +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/receivablePlan/index.ts b/src/api/crm/receivablePlan/index.ts index 178b21b5..f80f0572 100644 --- a/src/api/crm/receivablePlan/index.ts +++ b/src/api/crm/receivablePlan/index.ts @@ -2,7 +2,7 @@ import request from '@/config/axios' export interface ReceivablePlanVO { id: number - indexNo: number + period: number receivableId: number status: number checkStatus: string diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 1ffb38d6..ef86563b 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -27,6 +27,11 @@ export const getTenantIdByName = (name: string) => { return request.get({ url: '/system/tenant/get-id-by-name?name=' + name }) } +// 使用租户域名,获得租户信息 +export const getTenantByWebsite = (website: string) => { + return request.get({ url: '/system/tenant/get-by-website?website=' + website }) +} + // 登出 export const loginOut = () => { return request.post({ url: '/system/auth/logout' }) diff --git a/src/api/system/social/client/index.ts b/src/api/system/social/client/index.ts new file mode 100644 index 00000000..bf13ab49 --- /dev/null +++ b/src/api/system/social/client/index.ts @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface SocialClientVO { + id: number + name: string + socialType: number + userType: number + clientId: string + clientSecret: string + agentId: string + status: number +} + +// 查询社交客户端列表 +export const getSocialClientPage = async (params) => { + return await request.get({ url: `/system/social-client/page`, params }) +} + +// 查询社交客户端详情 +export const getSocialClient = async (id: number) => { + return await request.get({ url: `/system/social-client/get?id=` + id }) +} + +// 新增社交客户端 +export const createSocialClient = async (data: SocialClientVO) => { + return await request.post({ url: `/system/social-client/create`, data }) +} + +// 修改社交客户端 +export const updateSocialClient = async (data: SocialClientVO) => { + return await request.put({ url: `/system/social-client/update`, data }) +} + +// 删除社交客户端 +export const deleteSocialClient = async (id: number) => { + return await request.delete({ url: `/system/social-client/delete?id=` + id }) +} diff --git a/src/api/system/social/user/index.ts b/src/api/system/social/user/index.ts new file mode 100644 index 00000000..f11231b7 --- /dev/null +++ b/src/api/system/social/user/index.ts @@ -0,0 +1,24 @@ +import request from '@/config/axios' + +export interface SocialUserVO { + id: number + type: number + openid: string + token: string + rawTokenInfo: string + nickname: string + avatar: string + rawUserInfo: string + code: string + state: string +} + +// 查询社交用户列表 +export const getSocialUserPage = async (params) => { + return await request.get({ url: `/system/social-user/page`, params }) +} + +// 查询社交用户详情 +export const getSocialUser = async (id: number) => { + return await request.get({ url: `/system/social-user/get?id=` + id }) +} diff --git a/src/components/Card/src/CardTitle.vue b/src/components/Card/src/CardTitle.vue index 5b122f49..76a83564 100644 --- a/src/components/Card/src/CardTitle.vue +++ b/src/components/Card/src/CardTitle.vue @@ -3,7 +3,7 @@ defineComponent({ name: 'CardTitle' }) -const { title } = defineProps({ +defineProps({ title: { type: String, required: true diff --git a/src/components/ConfigGlobal/src/ConfigGlobal.vue b/src/components/ConfigGlobal/src/ConfigGlobal.vue index a0873967..5bd90cf1 100644 --- a/src/components/ConfigGlobal/src/ConfigGlobal.vue +++ b/src/components/ConfigGlobal/src/ConfigGlobal.vue @@ -1,20 +1,19 @@ - + + + diff --git a/src/components/DiyEditor/components/ComponentContainerProperty.vue b/src/components/DiyEditor/components/ComponentContainerProperty.vue new file mode 100644 index 00000000..5c5ed9a0 --- /dev/null +++ b/src/components/DiyEditor/components/ComponentContainerProperty.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue index 8e918fa9..2bcd81fd 100644 --- a/src/components/DiyEditor/components/ComponentLibrary.vue +++ b/src/components/DiyEditor/components/ComponentLibrary.vue @@ -1,5 +1,5 @@ - + diff --git a/src/components/DiyEditor/components/mobile/Carousel/property.vue b/src/components/DiyEditor/components/mobile/Carousel/property.vue index acaee35f..700e0005 100644 --- a/src/components/DiyEditor/components/mobile/Carousel/property.vue +++ b/src/components/DiyEditor/components/mobile/Carousel/property.vue @@ -1,103 +1,120 @@ diff --git a/src/layout/components/Message/src/Message.vue b/src/layout/components/Message/src/Message.vue index 28f796b3..3019df29 100644 --- a/src/layout/components/Message/src/Message.vue +++ b/src/layout/components/Message/src/Message.vue @@ -53,7 +53,7 @@ onMounted(() => { -
+ -
+
@@ -88,6 +88,7 @@ onMounted(() => { } .message-list { + height: 400px; display: flex; flex-direction: column; diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 5a818fa9..9fe429e9 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -116,6 +116,7 @@ export enum DICT_TYPE { SYSTEM_OAUTH2_GRANT_TYPE = 'system_oauth2_grant_type', SYSTEM_MAIL_SEND_STATUS = 'system_mail_send_status', SYSTEM_NOTIFY_TEMPLATE_TYPE = 'system_notify_template_type', + SYSTEM_SOCIAL_TYPE = 'system_social_type', // ========== INFRA 模块 ========== INFRA_BOOLEAN_STRING = 'infra_boolean_string', @@ -193,5 +194,6 @@ export enum DICT_TYPE { CRM_RETURN_TYPE = 'crm_return_type', CRM_CUSTOMER_INDUSTRY = 'crm_customer_industry', CRM_CUSTOMER_LEVEL = 'crm_customer_level', - CRM_CUSTOMER_SOURCE = 'crm_customer_source' + CRM_CUSTOMER_SOURCE = 'crm_customer_source', + CRM_PRODUCT_STATUS = 'crm_product_status' } diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts index 53ccda11..e2ffcadd 100644 --- a/src/utils/formatTime.ts +++ b/src/utils/formatTime.ts @@ -334,6 +334,6 @@ export function getLast1Year(): [dayjs.ConfigType, dayjs.ConfigType] { export function getDateRange( beginDate: dayjs.ConfigType, endDate: dayjs.ConfigType -): [dayjs.ConfigType, dayjs.ConfigType] { - return [dayjs(beginDate).startOf('d'), dayjs(endDate).endOf('d')] +): [string, string] { + return [dayjs(beginDate).startOf('d').toString(), dayjs(endDate).endOf('d').toString()] } diff --git a/src/utils/index.ts b/src/utils/index.ts index d5301ddb..10f57567 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -34,6 +34,13 @@ export const underlineToHump = (str: string): string => { }) } +/** + * 驼峰转横杠 + */ +export const humpToDash = (str: string): string => { + return str.replace(/([A-Z])/g, '-$1').toLowerCase() +} + export const setCssVar = (prop: string, val: any, dom = document.documentElement) => { dom.style.setProperty(prop, val) } @@ -67,7 +74,7 @@ export const trim = (str: string) => { * @param {Date | number | string} time 需要转换的时间 * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss */ -export const formatTime = (time: Date | number | string, fmt: string) => { +export function formatTime(time: Date | number | string, fmt: string) { if (!time) return '' else { const date = new Date(time) @@ -98,7 +105,7 @@ export const formatTime = (time: Date | number | string, fmt: string) => { /** * 生成随机字符串 */ -export const toAnyString = () => { +export function toAnyString() { const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => { const r: number = (Math.random() * 16) | 0 const v: number = c === 'x' ? r : (r & 0x3) | 0x8 @@ -107,6 +114,13 @@ export const toAnyString = () => { return str } +/** + * 首字母大写 + */ +export function firstUpperCase(str: string) { + return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase()) +} + export const generateUUID = () => { if (typeof crypto === 'object') { if (typeof crypto.randomUUID === 'function') { diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 9bee2523..ef212505 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -193,10 +193,10 @@ const loginData = reactive({ }) const socialList = [ - { icon: 'ant-design:github-filled', type: 0 }, { icon: 'ant-design:wechat-filled', type: 30 }, - { icon: 'ant-design:alipay-circle-filled', type: 0 }, - { icon: 'ant-design:dingtalk-circle-filled', type: 20 } + { icon: 'ant-design:dingtalk-circle-filled', type: 20 }, + { icon: 'ant-design:github-filled', type: 0 }, + { icon: 'ant-design:alipay-circle-filled', type: 0 } ] // 获取验证码 @@ -210,7 +210,7 @@ const getCode = async () => { verify.value.show() } } -//获取租户ID +// 获取租户 ID const getTenantId = async () => { if (loginData.tenantEnable === 'true') { const res = await LoginApi.getTenantIdByName(loginData.loginForm.tenantName) @@ -230,6 +230,15 @@ const getCookie = () => { } } } +// 根据域名,获得租户信息 +const getTenantByWebsite = async () => { + const website = location.host + const res = await LoginApi.getTenantByWebsite(website) + if (res) { + loginData.loginForm.tenantName = res.name + authUtil.setTenantId(res.id) + } +} const loading = ref() // ElLoading.service 返回的实例 // 登录 const handleLogin = async (params) => { @@ -278,10 +287,15 @@ const doSocialLogin = async (type: number) => { } else { loginLoading.value = true if (loginData.tenantEnable === 'true') { - await message.prompt('请输入租户名称', t('common.reminder')).then(async ({ value }) => { - const res = await LoginApi.getTenantIdByName(value) - authUtil.setTenantId(res) - }) + // 尝试先通过 tenantName 获取租户 + await getTenantId() + // 如果获取不到,则需要弹出提示,进行处理 + if (!authUtil.getTenantId()) { + await message.prompt('请输入租户名称', t('common.reminder')).then(async ({ value }) => { + const res = await LoginApi.getTenantIdByName(value) + authUtil.setTenantId(res) + }) + } } // 计算 redirectUri // tricky: type、redirect需要先encode一次,否则钉钉回调会丢失。 @@ -307,6 +321,7 @@ watch( ) onMounted(() => { getCookie() + getTenantByWebsite() }) diff --git a/src/views/Profile/Index.vue b/src/views/Profile/Index.vue index b05f93cc..8e1695b5 100644 --- a/src/views/Profile/Index.vue +++ b/src/views/Profile/Index.vue @@ -15,7 +15,7 @@
- + @@ -23,17 +23,18 @@ - +
-