diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..d0ec613 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,96 @@ +kind: pipeline +type: docker +name: build-deploy + +clone: + depth: 1 # ✅ 只拉取最近一次 commit,显著加快 clone 速度 + +trigger: + event: + - push + - custom + branch: + - master + - test + - feature/ldb_build + +steps: + - name: install & build + image: node:23.9.0 + volumes: + - name: build-output + path: /runner/builds + commands: + - corepack enable + - corepack prepare pnpm@8.15.5 --activate + - pnpm install + - mkdir -p /runner/builds/${DRONE_REPO_NAME}/${DRONE_BRANCH} + - | + case "${DRONE_BRANCH}" in + feature/ldb_build | test) + pnpm run build:test + ;; + master) + pnpm run build:prod + ;; + *) + echo "❌ 未配置此分支的构建规则: ${DRONE_BRANCH}" + exit 1 + ;; + esac + - rm -rf /runner/builds/${DRONE_REPO_NAME}/${DRONE_BRANCH}/* + - cp -r dist/* /runner/builds/${DRONE_REPO_NAME}/${DRONE_BRANCH}/ + + - name: deploy to spug + image: curlimages/curl + when: + status: + - success + branch: + - feature/ldb_build + - test + - master + environment: + SPUG_DEPLOY_URL: + from_secret: spug_deploy_lingji_work_fe_url + SPUG_DEPLOY_TOKEN: + from_secret: spug_deploy_token + commands: + - | + echo "🚀 部署到 Spug: 分支 ${DRONE_BRANCH}" + curl -X POST "$SPUG_DEPLOY_URL?name=${DRONE_BRANCH}&token=$SPUG_DEPLOY_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "ref": "refs/heads/'"${DRONE_BRANCH}"'", + "before": "'"${DRONE_COMMIT_BEFORE}"'", + "after": "'"${DRONE_COMMIT_SHA}"'", + "commits": [ + { + "message": "发布'"${DRONE_BRANCH}:${DRONE_COMMIT_SHA}"'" + } + ] + }' + + - name: notify feishu on failure + image: curlimages/curl + when: + status: + - failure + environment: + FEISHU_WEBHOOK: + from_secret: feishu_webhook_url + commands: + - | + curl -X POST "$FEISHU_WEBHOOK" \ + -H "Content-Type: application/json" \ + -d '{ + "msg_type": "text", + "content": { + "text": "❌ Drone-CI 执行失败 ❗️\n项目: '${DRONE_REPO_NAME}'\n分支: '${DRONE_BRANCH}'\n提交: '${DRONE_COMMIT_SHA:0:8}'" + } + }' + +volumes: + - name: build-output + host: + path: /www/dk_project/dk_compose/spug/data/repos/build/drone-runner/builds \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index a98f933..a78dbb9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -28,6 +28,14 @@ module.exports = { tsx: '@typescript-eslint/parser', }, }, + babelOptions: { + presets: [ + '@babel/preset-env' + ], + plugins: [ + '@vue/babel-plugin-jsx' + ] + }, rules: { '@typescript-eslint/prefer-optional-chain': 'off', 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', diff --git a/config/index.ts b/config/index.ts index 58a9509..5c96895 100644 --- a/config/index.ts +++ b/config/index.ts @@ -1,5 +1,5 @@ import { configUnocss } from './plugins'; -import { configAutoImport, configComponents, configIcons } from './unplugin'; +import { configAutoImport, configComponents,configIcons } from './unplugin'; import viteCompression from 'vite-plugin-compression'; import progress from 'vite-plugin-progress'; import defineOptions from 'unplugin-vue-define-options/vite'; diff --git a/config/unplugin/auto-import.ts b/config/unplugin/auto-import.ts index 69e7b9a..7778cc9 100644 --- a/config/unplugin/auto-import.ts +++ b/config/unplugin/auto-import.ts @@ -1,14 +1,9 @@ -/* - * @Author: RenXiaoDong - * @Date: 2025-06-24 16:29:10 - */ /** * 自动引入API * */ import AutoImport from 'unplugin-auto-import/vite'; import { ArcoResolver } from 'unplugin-vue-components/resolvers'; -import IconsResolver from 'unplugin-icons/resolver'; import { layoutsResolver } from '../utils'; @@ -21,7 +16,7 @@ export function configAutoImport() { '@vueuse/core', { dayjs: [['default', 'dayjs']], - 'lodash-es': ['cloneDeep', 'omit', 'pick', 'union', 'uniq', 'isNumber', 'uniqBy', 'isEmpty'], + 'lodash-es': ['cloneDeep', 'omit', 'pick', 'union', 'uniq', 'isNumber', 'uniqBy', 'isEmpty', 'merge', 'debounce'], '@/hooks': ['useModal'], }, ], @@ -31,9 +26,6 @@ export function configAutoImport() { enable: true, }, }), - IconsResolver({ - enabledCollections: [], - }), layoutsResolver(), ], eslintrc: { diff --git a/config/unplugin/component.ts b/config/unplugin/component.ts index 9840799..57b9dc8 100644 --- a/config/unplugin/component.ts +++ b/config/unplugin/component.ts @@ -5,7 +5,6 @@ import { kebabCase } from 'unplugin-vue-components'; import Components from 'unplugin-vue-components/vite'; import { ArcoResolver } from 'unplugin-vue-components/resolvers'; -import IconsResolver from 'unplugin-icons/resolver'; import { getSep, getPath, setResolve, layoutsResolver } from '../utils'; @@ -20,11 +19,6 @@ export function configComponents() { }, sideEffect: true, }), - IconsResolver({ - prefix: false, - customCollections: ['i'], - enabledCollections: [], - }), layoutsResolver(), { type: 'component', diff --git a/config/unplugin/icons.ts b/config/unplugin/icons.ts index 2afaffa..0c94bf2 100644 --- a/config/unplugin/icons.ts +++ b/config/unplugin/icons.ts @@ -1,14 +1,14 @@ -/** - * 自动引入 svg 图标 - * */ -import Icons from 'unplugin-icons/vite'; -import { FileSystemIconLoader } from 'unplugin-icons/loaders'; +// /** +// * 自动引入 svg 图标 +// * */ +import { resolve } from '../utils'; + +import { createSvgIconsPlugin } from "vite-plugin-svg-icons"; export function configIcons() { - return Icons({ - compiler: 'vue3', - customCollections: { - i: FileSystemIconLoader('./src/assets', (svg) => svg.replace(/^ -

退出登录后,你将无法收到该账号的通知

- 返回 + 返回 退出登录 @@ -83,15 +83,12 @@ defineExpose({ open }); } .cancel-btn { border-radius: 4px; - border: 1px solid var(--BG-500, #b1b2b5); - &:hover { - border: 1px solid var(--BG-500, #b1b2b5); - } } .danger-btn { - border-radius: 4px; background: var(--Functional-Danger-6, #f64b31) !important; - border: none !important; + &:hover { + background: var(--Functional-Danger-6, #f64b31) !important; + } } } } diff --git a/src/components/_base/navbar/components/navbar-menu/index.vue b/src/components/_base/navbar/components/navbar-menu/index.vue new file mode 100644 index 0000000..88953ff --- /dev/null +++ b/src/components/_base/navbar/components/navbar-menu/index.vue @@ -0,0 +1,93 @@ + + + + + + diff --git a/src/components/_base/navbar/components/navbar-menu/style.scss b/src/components/_base/navbar/components/navbar-menu/style.scss new file mode 100644 index 0000000..5a15e33 --- /dev/null +++ b/src/components/_base/navbar/components/navbar-menu/style.scss @@ -0,0 +1,45 @@ +.navbar-menu { + display: flex; + align-items: center; + margin-left: 40px; + .menu-item-text { + color: var(--Text-2, #3c4043); + font-family: $font-family-medium; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + :deep(.arco-menu) { + height: 100%; + .arco-menu-inner { + padding: 0 20px; + } + .arco-menu-item { + padding: 0; + position: relative; + &.arco-menu-selected { + .menu-item-text, + .arco-menu-selected-label { + color: #6d4cfe; + } + .arco-menu-selected-label { + background: var(--Brand-Brand-6, #6d4cfe); + height: 4px; + border-radius: 4px; + width: 50%; + position: absolute; + bottom: -8px; + left: 50%; + transform: translateX(-50%); + } + } + } + } + .arco-icon-down { + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + } + .arco-dropdown-open .arco-icon-down { + transform: rotate(180deg); + } +} diff --git a/src/components/_base/navbar/components/right-side/index.vue b/src/components/_base/navbar/components/right-side/index.vue new file mode 100644 index 0000000..4f187dd --- /dev/null +++ b/src/components/_base/navbar/components/right-side/index.vue @@ -0,0 +1,196 @@ + + + + + + diff --git a/src/components/_base/navbar/components/task-center-modal/components/export-task/constants.ts b/src/components/_base/navbar/components/task-center-modal/components/export-task/constants.ts new file mode 100644 index 0000000..1134c9a --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/export-task/constants.ts @@ -0,0 +1,38 @@ +export const INITIAL_FORM = { + type: 1, + operator_name: '', + module: '', + sort_column: undefined, + sort_order: undefined, +}; + +export const TABLE_COLUMNS = [ + { + title: '文件名称', + dataIndex: 'name', + width: 180, + }, + { + title: '所属模块', + dataIndex: 'module', + width: 120, + }, + { + title: '状态', + dataIndex: 'status', + width: 100, + }, + { + title: '创建时间', + dataIndex: 'created_at', + width: 180, + sortable: { + sortDirections: ['ascend', 'descend'], + }, + }, + { + title: '操作人员', + dataIndex: 'operator.name', + width: 150, + }, +]; diff --git a/src/components/_base/navbar/components/task-center-modal/components/export-task/delete-task-modal.vue b/src/components/_base/navbar/components/task-center-modal/components/export-task/delete-task-modal.vue new file mode 100644 index 0000000..e28a39a --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/export-task/delete-task-modal.vue @@ -0,0 +1,62 @@ + + + diff --git a/src/components/_base/navbar/components/task-center-modal/components/export-task/index.vue b/src/components/_base/navbar/components/task-center-modal/components/export-task/index.vue new file mode 100644 index 0000000..3e1a3bf --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/export-task/index.vue @@ -0,0 +1,386 @@ + + + diff --git a/src/components/_base/navbar/components/task-center-modal/components/export-task/style.scss b/src/components/_base/navbar/components/task-center-modal/components/export-task/style.scss new file mode 100644 index 0000000..6fe18d5 --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/export-task/style.scss @@ -0,0 +1,86 @@ +.export-task-wrap { + height: 100%; + display: flex; + flex-direction: column; + .tip-row { + border-radius: 2px; + background: #f0edff; + .label { + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + &.normal { + background: #ebf7f2; + .label { + color: #211f24; + } + } + &.abnormal { + background: #ffe7e4; + .label { + color: #211f24; + } + } + .err-btn { + background-color: #f64b31 !important; + color: var(--BG-white, #fff); + font-family: 'PingFang SC'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; + } + .operation-btn { + padding: 0; + cursor: pointer; + color: var(--Brand-Brand-6, #6d4cfe); + font-family: $font-family-regular; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + &:not(:last-child) { + margin-right: 16px; + } + &.red { + color: #f64b31; + } + } + } + .status-box { + border-radius: 2px; + display: flex; + height: 24px; + padding: 0px 8px; + align-items: center; + width: fit-content; + span { + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + &-0 { + background: var(--Functional-yellow-1, #fff7e5); + span { + color: var(--Functional-yellow-6, #ffae00); + } + } + &-1 { + background: var(--Functional-Green-1, #ebf7f2); + span { + color: var(--Functional-Green-6, #25c883); + } + } + &-2 { + background: var(--Functional-Red-1, #ffe9e7); + span { + color: var(--Functional-Red-6, #f64b31); + } + } + } +} diff --git a/src/components/_base/navbar/components/task-center-modal/components/import-task/constants.ts b/src/components/_base/navbar/components/task-center-modal/components/import-task/constants.ts new file mode 100644 index 0000000..633bb88 --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/import-task/constants.ts @@ -0,0 +1,53 @@ +export const INITIAL_FORM = { + type: 0, + operator_name: '', + module: '', + sort_column: undefined, + sort_order: undefined, +}; + +export const TABLE_COLUMNS = [ + { + title: '任务名称', + dataIndex: 'name', + width: 180, + }, + { + title: '所属模块', + dataIndex: 'module', + width: 120, + }, + { + title: '状态', + dataIndex: 'status', + width: 100, + }, + { + title: '共导入', + dataIndex: 'total_number', + width: 100, + }, + { + title: '导入成功', + dataIndex: 'success_number', + width: 100, + }, + { + title: '导入失败', + dataIndex: 'fail_number', + width: 100, + }, + { + title: '导入时间', + dataIndex: 'created_at', + width: 180, + sortable: { + sortDirections: ['ascend', 'descend'], + }, + }, + { + title: '操作人员', + dataIndex: 'operator.name', + width: 150, + }, +]; diff --git a/src/components/_base/navbar/components/task-center-modal/components/import-task/delete-task-modal.vue b/src/components/_base/navbar/components/task-center-modal/components/import-task/delete-task-modal.vue new file mode 100644 index 0000000..1c7c09e --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/import-task/delete-task-modal.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/components/_base/navbar/components/task-center-modal/components/import-task/index.vue b/src/components/_base/navbar/components/task-center-modal/components/import-task/index.vue new file mode 100644 index 0000000..05de549 --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/import-task/index.vue @@ -0,0 +1,300 @@ + + + diff --git a/src/components/_base/navbar/components/task-center-modal/components/import-task/style.scss b/src/components/_base/navbar/components/task-center-modal/components/import-task/style.scss new file mode 100644 index 0000000..216880a --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/components/import-task/style.scss @@ -0,0 +1,86 @@ +.import-task-wrap { + height: 100%; + display: flex; + flex-direction: column; + .tip-row { + border-radius: 2px; + background: #f0edff; + .label { + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + &.normal { + background: #ebf7f2; + .label { + color: #211f24; + } + } + &.abnormal { + background: #ffe7e4; + .label { + color: #211f24; + } + } + .err-btn { + background-color: #f64b31 !important; + color: var(--BG-white, #fff); + font-family: 'PingFang SC'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; + } + .operation-btn { + padding: 0; + cursor: pointer; + color: var(--Brand-Brand-6, #6d4cfe); + font-family: $font-family-regular; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + &:not(:last-child) { + margin-right: 16px; + } + &.red { + color: #f64b31; + } + } + } + .status-box { + border-radius: 2px; + display: flex; + height: 24px; + padding: 0px 8px; + align-items: center; + width: fit-content; + span { + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + &-0 { + background: var(--Functional-yellow-1, #fff7e5); + span { + color: var(--Functional-yellow-6, #ffae00); + } + } + &-1 { + background: var(--Functional-Green-1, #ebf7f2); + span { + color: var(--Functional-Green-6, #25c883); + } + } + &-2 { + background: var(--Functional-Red-1, #ffe9e7); + span { + color: var(--Functional-Red-6, #f64b31); + } + } + } +} diff --git a/src/components/_base/navbar/components/task-center-modal/constants.ts b/src/components/_base/navbar/components/task-center-modal/constants.ts new file mode 100644 index 0000000..63ceaa0 --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/constants.ts @@ -0,0 +1,34 @@ +export enum enumTaskStatus { + Exporting = 0, // 导出中 + Finished = 1, // 已完成 + Failed = 2, // 导出失败 +} + +export const EXPORT_TASK_STATUS = [ + { + label: '导出中', + value: enumTaskStatus.Exporting, + }, + { + label: '已完成', + value: enumTaskStatus.Finished, + }, + { + label: '导出失败', + value: enumTaskStatus.Failed, + }, +]; +export const IMPORT_TASK_STATUS = [ + { + label: '导入中', + value: enumTaskStatus.Exporting, + }, + { + label: '已完成', + value: enumTaskStatus.Finished, + }, + { + label: '导入失败', + value: enumTaskStatus.Failed, + }, +]; diff --git a/src/components/_base/navbar/components/task-center-modal/index.vue b/src/components/_base/navbar/components/task-center-modal/index.vue new file mode 100644 index 0000000..09815c7 --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/index.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/_base/navbar/components/task-center-modal/style.scss b/src/components/_base/navbar/components/task-center-modal/style.scss new file mode 100644 index 0000000..25c5e3b --- /dev/null +++ b/src/components/_base/navbar/components/task-center-modal/style.scss @@ -0,0 +1,77 @@ +.task-center-modal { + .arco-modal-header { + border-bottom: none !important; + .arco-modal-title { + color: var(--Text-1, #211f24); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; + font-family: $font-family-medium; + } + } + .arco-modal-body { + padding: 0 !important; + display: flex; + flex-direction: column; + height: 650px; + .filter-row { + .filter-row-item { + &:not(:last-child) { + margin-right: 24px; + } + .label { + margin-right: 12px; + color: #211f24; + font-family: $font-family-regular; + font-size: 14px; + font-style: normal; + font-weight: 400; + flex-shrink: 0; + line-height: 22px; /* 157.143% */ + } + :deep(.arco-space-item) { + width: 100%; + } + } + } + .arco-tabs { + .arco-tabs-nav-top { + .arco-tabs-tab { + margin: 0 20px; + .arco-tabs-tab-title { + color: var(--Text-2, #3c4043); + font-family: $font-family-regular; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + &.arco-tabs-tab-active { + .arco-tabs-tab-title { + color: #6D4CFE; + font-family: $font-family-medium; + } + } + } + } + .arco-tabs-content { + display: none; + } + } + .content { + flex: 1; + padding: 24px 20px; + overflow: hidden; + } + } + + .cts { + color: var(--Text-1, #211f24); + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } +} diff --git a/src/components/_base/navbar/index.vue b/src/components/_base/navbar/index.vue index 6122ae8..2f6507a 100644 --- a/src/components/_base/navbar/index.vue +++ b/src/components/_base/navbar/index.vue @@ -1,255 +1,47 @@ - - + - - diff --git a/src/views/components/dataEngine/keyWord.vue b/src/views/components/dataEngine/keyWord.vue index 6c2899d..c462718 100644 --- a/src/views/components/dataEngine/keyWord.vue +++ b/src/views/components/dataEngine/keyWord.vue @@ -260,7 +260,7 @@
@@ -713,14 +713,6 @@ onMounted(() => { justify-content: flex-end; align-items: center; border-top: 1px solid var(--Border-1, #d7d7d9); - .cancel-btn { - border-radius: 4px; - border: 1px solid var(--BG-500, #b1b2b5); - background: var(--BG-white, #fff); - &:hover { - border: 1px solid var(--BG-500, #b1b2b5); - } - } } } diff --git a/src/views/components/dataEngine/userPainPoints.vue b/src/views/components/dataEngine/userPainPoints.vue index 52b5fb5..e8cd5ca 100644 --- a/src/views/components/dataEngine/userPainPoints.vue +++ b/src/views/components/dataEngine/userPainPoints.vue @@ -110,7 +110,7 @@ @@ -318,14 +318,6 @@ const search = () => { justify-content: flex-end; align-items: center; border-top: 1px solid var(--Border-1, #d7d7d9); - .cancel-btn { - border-radius: 4px; - border: 1px solid var(--BG-500, #b1b2b5); - background: var(--BG-white, #fff); - &:hover { - border: 1px solid var(--BG-500, #b1b2b5); - } - } } } diff --git a/src/views/components/dataEngine/userPersona.vue b/src/views/components/dataEngine/userPersona.vue index ee736a0..53a053a 100644 --- a/src/views/components/dataEngine/userPersona.vue +++ b/src/views/components/dataEngine/userPersona.vue @@ -18,16 +18,16 @@ 女性 - {{ genderData[0].rate * 100 }}% + {{ (girlData.rate * 100).toFixed(2) }}% TGI - {{ genderData[0].tgi }} + {{ girlData.tgi }} 男性 - {{ genderData[1].rate * 100 }}% + {{ (boyData.rate * 100).toFixed(2) }}% TGI - {{ genderData[1].tgi }} + {{ boyData.tgi }} @@ -145,10 +145,13 @@ const topHeaderRef = ref(); const selectedIndustry = computed(() => topHeaderRef.value?.selectedIndustry); const selectedSubCategory = computed(() => topHeaderRef.value?.selectedSubCategory); const selectedTimePeriod = computed(() => topHeaderRef.value?.selectedTimePeriod); + const genderData = ref([]); const genderValueData = ref([]); const ageValueData = ref([]); const geoList = ref([]); +const boyData = computed(() => genderData.value.find( v => v.gender === 1) ?? {}) +const girlData = computed(() => genderData.value.find( v => v.gender === 2) ?? {}) // 监听筛选条件变化 watch([selectedIndustry, selectedTimePeriod, selectedSubCategory], () => { getAgeDistributionsList(); @@ -233,7 +236,7 @@ const getGenderDistributionsList = async () => { await nextTick(); genderValueData.value = data.map((item) => ({ - value: item.rate * 100, + value: (item.rate * 100).toFixed(2), tgi: item.tgi, name: item.gender === 1 ? '女性' : '男性', })); diff --git a/src/views/components/login/index.vue b/src/views/components/login/index.vue index efdf9ba..238c240 100644 --- a/src/views/components/login/index.vue +++ b/src/views/components/login/index.vue @@ -54,16 +54,15 @@ -
{{ isLogin ? '登录' : '注册并开通企业账号' }} -
+
@@ -126,13 +125,16 @@ diff --git a/src/views/property-marketing/media-account/account-detail/style.scss b/src/views/property-marketing/media-account/account-detail/style.scss index 8b5ad4b..40d5a29 100644 --- a/src/views/property-marketing/media-account/account-detail/style.scss +++ b/src/views/property-marketing/media-account/account-detail/style.scss @@ -19,16 +19,6 @@ padding: 10px 0; align-items: center; } - :deep(.search-btn) { - border-radius: 4px; - border: 1px solid var(--Brand-Brand-6, #6d4cfe); - color: #6d4cfe; - } - :deep(.reset-btn) { - border-radius: 4px; - border: 1px solid var(--BG-500, #b1b2b5); - background: var(--BG-white, #fff); - } .table-wrap { width: 100%; diff --git a/src/views/property-marketing/media-account/account-manage/components/account-table/delete-account.vue b/src/views/property-marketing/media-account/account-manage/components/account-table/delete-account.vue index ac6f06e..071f7a6 100644 --- a/src/views/property-marketing/media-account/account-manage/components/account-table/delete-account.vue +++ b/src/views/property-marketing/media-account/account-manage/components/account-table/delete-account.vue @@ -15,7 +15,7 @@ 确认删除 {{ accountName }} 这个账号吗? diff --git a/src/views/property-marketing/put-account/account-manage/components/account-table/pause-account-patch.vue b/src/views/property-marketing/put-account/account-manage/components/account-table/pause-account-patch.vue index 9649f20..671542f 100644 --- a/src/views/property-marketing/put-account/account-manage/components/account-table/pause-account-patch.vue +++ b/src/views/property-marketing/put-account/account-manage/components/account-table/pause-account-patch.vue @@ -9,7 +9,7 @@ 确认暂停同步 “{{ accountName }}” 这个账号的数据吗? @@ -20,8 +20,8 @@ import { ref } from 'vue'; import { pausePatchPlacementAccount } from '@/api/all/propertyMarketing'; import icon1 from '@/assets/img/media-account/icon-warn-1.png'; -const emits = defineEmits(['update', 'close']); - +const emits = defineEmits(['close']); +const update = inject('update'); const visible = ref(false); const accountId = ref(null); const accountName = ref(''); @@ -45,7 +45,7 @@ async function onConfirm() { const { code } = await pausePatchPlacementAccount(accountId.value); if (code === 200) { AMessage.success('暂停成功'); - emits('update'); + update(); onClose(); } } diff --git a/src/views/property-marketing/put-account/account-manage/components/account-table/style.scss b/src/views/property-marketing/put-account/account-manage/components/account-table/style.scss index 8bb6a61..3ddc4d9 100644 --- a/src/views/property-marketing/put-account/account-manage/components/account-table/style.scss +++ b/src/views/property-marketing/put-account/account-manage/components/account-table/style.scss @@ -1,9 +1,3 @@ -@mixin ellipsis { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .card-container { flex: 1; display: grid; diff --git a/src/views/property-marketing/put-account/account-manage/components/add-account-modal/index.vue b/src/views/property-marketing/put-account/account-manage/components/add-account-modal/index.vue index 021d701..7f0aa6e 100644 --- a/src/views/property-marketing/put-account/account-manage/components/add-account-modal/index.vue +++ b/src/views/property-marketing/put-account/account-manage/components/add-account-modal/index.vue @@ -111,6 +111,9 @@ + + + - + - + @@ -148,20 +151,26 @@ import { ref, defineEmits } from 'vue'; import AuthorizedAccountModal from '../authorized-account-modal'; // import ImportPromptModal from '../import-prompt-modal'; import StatusBox from '../status-box'; -import { PLATFORM_LIST } from '@/views/property-marketing/put-account/common_constants'; +import CommonSelect from '@/components/common-select'; +import { PLATFORM_LIST, ENUM_PUT_ACCOUNT_PLATFORM } from '@/utils/platform'; + +import { showExportNotification } from '@/utils/arcoD'; +import { genRandomId } from '@/utils/tools'; import { postPlacementAccounts, getPlacementAccountsDetail, putPlacementAccounts, getPlacementAccountsTemplateUrl, batchPlacementAccounts, + getProjectList, } from '@/api/all/propertyMarketing'; import icon1 from '@/assets/img/media-account/icon-download.png'; import icon2 from '@/assets/img/media-account/icon-delete.png'; -const emits = defineEmits(['update']); +const update = inject('update'); +const emits = defineEmits(['startQueryTaskStatus']); const UploadStatus = { DEFAULT: 'default', @@ -173,7 +182,8 @@ const INITIAL_FORM = { operator_name: '', holder_name: '', platform: 0, - is_sync_project: 0, + is_sync_project: 1, + project_ids: [], }; const visible = ref(false); @@ -188,6 +198,8 @@ const authorizedAccountModalRef = ref(null); const uploadRef = ref(null); const file = ref(null); const form = ref(cloneDeep(INITIAL_FORM)); +const projects = ref([]); +const importLoading = ref(false); const rules = { mobile: [ @@ -213,7 +225,7 @@ const rules = { const isBatchImport = computed(() => uploadType.value === 'batch'); const confirmBtnText = computed(() => { - if (isBatchImport.value) return '确定导入'; + if (isBatchImport.value) return importLoading.value ? '导入中' : '确定导入'; return isEdit.value ? '确定' : '下一步'; }); @@ -229,6 +241,7 @@ const handleUpload = async (option) => { function removeFile() { fileName.value = ''; file.value = null; + importLoading.value = false; uploadStatus.value = UploadStatus.DEFAULT; } @@ -240,6 +253,8 @@ const reset = () => { fileName.value = ''; file.value = null; isEdit.value = false; + projects.value = []; + importLoading.value = false; uploadStatus.value = UploadStatus.DEFAULT; uploadType.value = 'manual'; }; @@ -252,12 +267,19 @@ const open = (accountId = '') => { id.value = accountId; isEdit.value = !!accountId; + getProjects(); if (accountId) { getAccountDetail(); } visible.value = true; }; +const getProjects = async () => { + const { code, data } = await getProjectList(); + if (code === 200) { + projects.value = data; + } +}; const getAccountDetail = async () => { const { code, data } = await getPlacementAccountsDetail(id.value); @@ -268,28 +290,59 @@ const getAccountDetail = async () => { const handleBatchImport = async () => { try { + if (!file.value) { + AMessage.warning('请上传要导入的文件'); + return; + } + + importLoading.value = true; const formData = new FormData(); formData.append('file', file.value); - const { code } = await batchPlacementAccounts(formData, { + const { code, data } = await batchPlacementAccounts(formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); + if (code === 200) { - AMessage.success('导入成功'); - emits('update'); + const id = genRandomId(); + showExportNotification(`正在导入“${file.value.name}”,请稍后...`, { id }); + emit('startQueryTaskStatus', data.id, id); onClose(); } else { uploadStatus.value = UploadStatus.ERROR; } } catch (error) { uploadStatus.value = UploadStatus.ERROR; + } finally { + importLoading.value = false; } // importPromptModalRef.value.open(); }; +const handleAdd = async () => { + // 聚光无子账号 + if (form.value.platform === ENUM_PUT_ACCOUNT_PLATFORM.jg) { + const { code, data } = await postPlacementAccounts(form.value); + if (code === 200) { + update(); + authorizedAccountModalRef.value.open({ accountId: data?.id }); + } + } else { + authorizedAccountModalRef.value.open({ form: form.value, needSelectSubAccount: true }); + } +}; +const handleEdit = async () => { + const { code } = await putPlacementAccounts({ id: id.value, ...form.value }); + if (code === 200) { + isEdit.value && AMessage.success('修改成功'); + update(); + onClose(); + } +}; + async function onSubmit() { if (isBatchImport.value) { handleBatchImport(); @@ -298,27 +351,11 @@ async function onSubmit() { formRef.value.validate(async (errors) => { if (!errors) { - const _fn = id.value ? putPlacementAccounts : postPlacementAccounts; - const _params = id.value ? { id: id.value, ...form.value } : form.value; - const { code, data } = await _fn(_params); - if (code === 200) { - isEdit.value && AMessage.success('修改成功'); - emits('update'); - - if (isEdit.value) { - onClose(); - } else { - handleSuccess(data?.id); - } - } + isEdit.value ? handleEdit() : handleAdd(); } }); } -const handleSuccess = (id) => { - authorizedAccountModalRef.value.open(id); -}; - const handleDownloadTemplate = async () => { const { code, data } = await getPlacementAccountsTemplateUrl(); if (code === 200) { @@ -326,6 +363,7 @@ const handleDownloadTemplate = async () => { } }; +provide('closeAddAccountModal', onClose); // 对外暴露打开弹窗方法 defineExpose({ open }); diff --git a/src/views/property-marketing/put-account/account-manage/components/authorized-account-modal/index.vue b/src/views/property-marketing/put-account/account-manage/components/authorized-account-modal/index.vue index 4f5bb36..8ac7abc 100644 --- a/src/views/property-marketing/put-account/account-manage/components/authorized-account-modal/index.vue +++ b/src/views/property-marketing/put-account/account-manage/components/authorized-account-modal/index.vue @@ -12,7 +12,7 @@ :footer="!isLoading" @close="close" > -
+ +
diff --git a/src/views/property-marketing/put-account/account-manage/components/filter-block/style.scss b/src/views/property-marketing/put-account/account-manage/components/filter-block/style.scss index 7814361..48e2115 100644 --- a/src/views/property-marketing/put-account/account-manage/components/filter-block/style.scss +++ b/src/views/property-marketing/put-account/account-manage/components/filter-block/style.scss @@ -1,17 +1,4 @@ .container { - :deep(.arco-input-wrapper), - :deep(.arco-select-view-single), - :deep(.arco-select-view-multiple) { - border-radius: 4px; - border-color: #d7d7d9; - background-color: #fff; - &:focus-within, - &.arco-input-focus { - background-color: var(--color-bg-2); - border-color: rgb(var(--primary-6)); - box-shadow: 0 0 0 0 var(--color-primary-light-2); - } - } .filter-row { .filter-row-item { &:not(:last-child) { diff --git a/src/views/property-marketing/put-account/account-manage/components/import-prompt-modal/index.vue b/src/views/property-marketing/put-account/account-manage/components/import-prompt-modal/index.vue index 5fd6c1e..ac7f68c 100644 --- a/src/views/property-marketing/put-account/account-manage/components/import-prompt-modal/index.vue +++ b/src/views/property-marketing/put-account/account-manage/components/import-prompt-modal/index.vue @@ -18,7 +18,7 @@
diff --git a/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/constants.ts b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/constants.ts new file mode 100644 index 0000000..52e05fd --- /dev/null +++ b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/constants.ts @@ -0,0 +1,23 @@ +export const INITIAL_FORM = { + platform: '', + account: '', + password: '', + account_name: '', + account_id: '', +}; +export const INITIAL_PAGE_INFO = { + page: 1, + page_size: 20, + total: 0, +}; + +export const TABLE_COLUMNS = [ + { + title: '账户名称', + dataIndex: 'account_name', + }, + { + title: '账户ID', + dataIndex: 'account_id', + }, +]; diff --git a/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/index.vue b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/index.vue new file mode 100644 index 0000000..d2af440 --- /dev/null +++ b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/index.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/style.scss b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/style.scss new file mode 100644 index 0000000..d8c0813 --- /dev/null +++ b/src/views/property-marketing/put-account/account-manage/components/select-sub-account-modal/style.scss @@ -0,0 +1,45 @@ +.select-sub-account-modal { + .cts { + color: var(--Text-1, #211f24); + font-family: $font-family-medium; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + .arco-modal-header { + } + .arco-modal-body { + height: 536px; + overflow: hidden; + display: flex; + flex-direction: column; + .filter-row { + .filter-row-item { + &:not(:last-child) { + margin-right: 24px; + } + .label { + margin-right: 12px; + color: #211f24; + font-family: $font-family-regular; + font-size: 14px; + font-style: normal; + font-weight: 400; + flex-shrink: 0; + line-height: 22px; + } + } + } + + } + .arco-modal-footer { + justify-content: space-between; + .s1 { + font-family: $font-family-regular; + .num { + font-family: $font-family-medium; + } + } + } +} diff --git a/src/views/property-marketing/put-account/account-manage/components/status-box/index.vue b/src/views/property-marketing/put-account/account-manage/components/status-box/index.vue index bc5362f..6599f0f 100644 --- a/src/views/property-marketing/put-account/account-manage/components/status-box/index.vue +++ b/src/views/property-marketing/put-account/account-manage/components/status-box/index.vue @@ -13,7 +13,7 @@ @@ -75,7 +75,7 @@ const isDisabledReauthorize = (status) => { } } - &-2, + &-3, &-4, &-5, &-6 { @@ -85,7 +85,7 @@ const isDisabledReauthorize = (status) => { } } - &-3 { + &-2{ background: #fff7e5; color: #ffae00; .text { diff --git a/src/views/property-marketing/put-account/account-manage/constants.ts b/src/views/property-marketing/put-account/account-manage/constants.ts index be17120..e6afd6e 100644 --- a/src/views/property-marketing/put-account/account-manage/constants.ts +++ b/src/views/property-marketing/put-account/account-manage/constants.ts @@ -8,4 +8,5 @@ export const INITIAL_QUERY = { status: '', platform: '', operator_id: '', + project_ids: [], }; diff --git a/src/views/property-marketing/put-account/account-manage/index.vue b/src/views/property-marketing/put-account/account-manage/index.vue index d0b4a33..e110d61 100644 --- a/src/views/property-marketing/put-account/account-manage/index.vue +++ b/src/views/property-marketing/put-account/account-manage/index.vue @@ -8,7 +8,7 @@

账户管理

- + @@ -53,7 +53,7 @@
- + @@ -67,7 +67,6 @@ @selectionChange="handleSelectionChange" @delete="handleDelete" @openEdit="handleOpenEdit" - @update="getData" /> @@ -77,16 +76,17 @@ size="mini" show-total show-jumper - :show-page-size="false" + show-page-size + :page-size-options="[8, 16, 20, 32, 64]" :current="pageInfo.page" - :page-size="pageInfo.pageSize" + :page-size="pageInfo.page_size" @change="onPageChange" @page-size-change="onPageSizeChange" />
- +
@@ -96,11 +96,13 @@ import { ref } from 'vue'; import FilterBlock from './components/filter-block'; import AccountTable from './components/account-table'; -import AddAccountModal from './components/add-account-modal'; +import AddPutAccountModal from './components/add-account-modal'; import DeleteAccountModal from './components/account-table/delete-account'; import { INITIAL_QUERY } from './constants'; import { getPlacementAccounts, getPlacementAccountsHealth } from '@/api/all/propertyMarketing'; +import { getTaskStatus } from '@/api/all/common'; +import { showImportResultNotification } from '@/utils/arcoD'; import icon1 from '@/assets/img/media-account/icon-add.png'; import icon4 from '@/assets/img/media-account/icon-success.png'; @@ -111,10 +113,11 @@ const groupManageModalRef = ref(null); const tagsManageModalRef = ref(null); const addAccountModalRef = ref(null); const deleteAccountRef = ref(null); +let queryTaskTimer = null; const pageInfo = ref({ page: 1, - pageSize: 8, + page_size: 20, total: 0, }); const query = ref(cloneDeep(INITIAL_QUERY)); @@ -140,6 +143,7 @@ const tipLabel = computed(() => { too_many_requests_number = 0, account_frozen_number = 0, miss_data_number = 0, + abnormal_number = 0, } = healthData.value; // 定义异常类型映射 @@ -148,6 +152,7 @@ const tipLabel = computed(() => { { count: too_many_requests_number, label: '请求频繁' }, { count: account_frozen_number, label: '账号被封' }, { count: miss_data_number, label: '数据缺失' }, + { count: abnormal_number, label: '其他异常' }, ]; // 过滤出有异常的项并格式化 @@ -156,10 +161,6 @@ const tipLabel = computed(() => { return `共有 ${total_abnormal_number} 个账号存在授权异常,其中:${abnormalLabels.join(',')}。`; }); -onMounted(() => { - getData(); -}); - const getData = () => { getHealthData(); getAccountData(); @@ -172,10 +173,10 @@ const getHealthData = async () => { } }; const getAccountData = async () => { - const { page, pageSize } = pageInfo.value; + const { page, page_size } = pageInfo.value; const { code, data, total } = await getPlacementAccounts({ page, - page_size: pageSize, + page_size, ...query.value, }); if (code === 200) { @@ -188,11 +189,11 @@ const reload = () => { getData(); }; const handleSearch = () => { - getData(); + reload(); }; const handleReset = () => { pageInfo.value.page = 1; - pageInfo.value.pageSize = 20; + pageInfo.value.page_size = 20; pageInfo.value.total = 0; selectedItems.value = []; query.value = cloneDeep(INITIAL_QUERY); @@ -204,7 +205,7 @@ const onPageChange = (current) => { getData(); }; const onPageSizeChange = (pageSize) => { - pageInfo.value.pageSize = pageSize; + pageInfo.value.page_size = pageSize; reload(); }; @@ -254,6 +255,39 @@ const handleOpenAbnormalAccount = () => { query.value.status = 2; reload(); }; + +// 查询导入账号任务状态 +const getSyncTaskStatus = async (id, notificationId) => { + const { code, data } = await getTaskStatus(id); + if (code === 200) { + if (data?.status !== 0) { + clearQueryTaskTimer(); + notificationId && Notification.remove(notificationId); + showImportResultNotification(data); + getData(); + } + } +}; +const handleGetImportTaskStatus = (id, notificationId) => { + clearQueryTaskTimer(); + getSyncTaskStatus(id, notificationId); + queryTaskTimer = setInterval(() => getSyncTaskStatus(id, notificationId), 3000); +}; +const clearQueryTaskTimer = () => { + if (queryTaskTimer) { + clearInterval(queryTaskTimer); + queryTaskTimer = null; + } +}; + +onMounted(() => { + getData(); +}); +onUnmounted(() => { + clearQueryTaskTimer(); +}); + +provide('update', getData);