feat: 媒体账号/投放账户增加【所属项目】相关逻辑
This commit is contained in:
@ -377,6 +377,11 @@ export const getProjects = (params = {}) => {
|
|||||||
return Http.get('/v1/projects', params);
|
return Http.get('/v1/projects', params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 项目管理-列表
|
||||||
|
export const getProjectList = () => {
|
||||||
|
return Http.get('/v1/projects/list');
|
||||||
|
};
|
||||||
|
|
||||||
// 项目管理-删除
|
// 项目管理-删除
|
||||||
export const deleteProject = (id: string) => {
|
export const deleteProject = (id: string) => {
|
||||||
return Http.delete(`/v1/projects/${id}`);
|
return Http.delete(`/v1/projects/${id}`);
|
||||||
|
|||||||
@ -4,12 +4,12 @@
|
|||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<a-select
|
<a-select
|
||||||
v-model="selectedGroups"
|
v-model="selectedValues"
|
||||||
:multiple="multiple"
|
:multiple="multiple"
|
||||||
size="medium"
|
size="medium"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
allow-clear
|
allow-clear
|
||||||
:max-tag-count="3"
|
:max-tag-count="maxTagCount"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
||||||
@ -38,27 +38,30 @@ const props = defineProps({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
maxTagCount: {
|
||||||
|
type: Number,
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue', 'change']);
|
const emits = defineEmits(['update:modelValue', 'change']);
|
||||||
|
|
||||||
const selectedGroups = ref(props.multiple ? [] : '');
|
const selectedValues = ref(props.multiple ? [] : '');
|
||||||
|
|
||||||
// 监听外部传入的值变化
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
selectedGroups.value = newVal;
|
selectedValues.value = newVal;
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
// 监听内部值变化,向外部发送更新
|
|
||||||
watch(selectedGroups, (newVal) => {
|
watch(selectedValues, (newVal) => {
|
||||||
emits('update:modelValue', newVal);
|
emits('update:modelValue', newVal);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleChange = (value) => {
|
const handleChange = (value) => {
|
||||||
selectedGroups.value = value;
|
selectedValues.value = value;
|
||||||
emits('change', value);
|
emits('change', value);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">分组</span>
|
<span class="label">分组</span>
|
||||||
<a-space class="w-200px">
|
<a-space class="w-200px">
|
||||||
<GroupSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
<CommonSelect v-model="query.group_ids" :options="groups" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -66,9 +66,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, defineEmits, defineProps } from 'vue';
|
import { reactive, defineEmits, defineProps } from 'vue';
|
||||||
import { fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
import { fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
||||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
|
||||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select';
|
|
||||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||||
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
query: {
|
query: {
|
||||||
|
|||||||
@ -46,6 +46,30 @@
|
|||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<span class="cts">{{ item.operator?.name || '-' }}</span>
|
<span class="cts">{{ item.operator?.name || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<span class="label">所属项目</span>
|
||||||
|
<span v-if="!item.projects.length" class="cts">-</span>
|
||||||
|
<div v-else class="flex items-center">
|
||||||
|
<a-tooltip
|
||||||
|
v-if="item.projects.length > 2"
|
||||||
|
position="bottom"
|
||||||
|
:content="
|
||||||
|
item.projects
|
||||||
|
.slice(2)
|
||||||
|
.map((v) => v.name)
|
||||||
|
.join(',')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="tag-box">
|
||||||
|
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<div v-for="(project, index) in item.projects.slice(0, 2)" :key="index" class="tag-box">
|
||||||
|
<span class="text">{{ project.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="field-row">
|
<div class="field-row">
|
||||||
<span class="label">分组</span>
|
<span class="label">分组</span>
|
||||||
<span class="cts">{{ item.group?.name || '-' }}</span>
|
<span class="cts">{{ item.group?.name || '-' }}</span>
|
||||||
@ -76,7 +100,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="operate-row">
|
<div class="operate-row">
|
||||||
<a-dropdown trigger="hover">
|
<a-dropdown trigger="hover">
|
||||||
<a-button class="w-52px mr-8px" type="outline" size="mini">
|
<a-button class="w-52px mr-8px" type="outline" size="mini">
|
||||||
<template #default>更多</template>
|
<template #default>更多</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
@ -89,7 +113,7 @@
|
|||||||
>
|
>
|
||||||
<a-doption class="color-#F64B31" @click="openDelete(item)">删除</a-doption>
|
<a-doption class="color-#F64B31" @click="openDelete(item)">删除</a-doption>
|
||||||
</template>
|
</template>
|
||||||
<a-button type="outline" size="mini" @click="onBtnClick(item)">
|
<a-button type="outline" size="mini" @click="onBtnClick(item)">
|
||||||
<template #default>{{ getBtnText(item) }}</template>
|
<template #default>{{ getBtnText(item) }}</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
@ -101,8 +125,8 @@
|
|||||||
<span class="name !mb-0">更新数据失败</span>
|
<span class="name !mb-0">更新数据失败</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<a-button type="outline" class="mr-8px" size="mini" @click="onDeleteSyncStatus(item)">取消</a-button>
|
<a-button type="outline" class="mr-8px" size="mini" @click="onDeleteSyncStatus(item)">取消</a-button>
|
||||||
<a-button type="outline" class="" size="mini" @click="syncData(item)">重新更新</a-button>
|
<a-button type="outline" class="" size="mini" @click="syncData(item)">重新更新</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
@ -174,7 +198,7 @@ const isSyncing = (item) => {
|
|||||||
if (!props.syncMediaAccounts.length) return false;
|
if (!props.syncMediaAccounts.length) return false;
|
||||||
|
|
||||||
const target = props.syncMediaAccounts.find((v) => v.id === item.id);
|
const target = props.syncMediaAccounts.find((v) => v.id === item.id);
|
||||||
if(target) {
|
if (target) {
|
||||||
return target?.status === 0;
|
return target?.status === 0;
|
||||||
}
|
}
|
||||||
return target?.status === 0;
|
return target?.status === 0;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
@mixin ellipsis {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container {
|
.card-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -19,12 +19,11 @@ import {
|
|||||||
Message as AMessage,
|
Message as AMessage,
|
||||||
Textarea,
|
Textarea,
|
||||||
} from '@arco-design/web-vue';
|
} from '@arco-design/web-vue';
|
||||||
import TagSelect from '@/views/property-marketing/media-account/components/tag-select';
|
|
||||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
|
||||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||||
import ImportPromptModal from '../import-prompt-modal';
|
import ImportPromptModal from '../import-prompt-modal';
|
||||||
import StatusBox from '../status-box';
|
import StatusBox from '../status-box';
|
||||||
import SyncDataModal from '../sync-data-modal';
|
import SyncDataModal from '../sync-data-modal';
|
||||||
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
import icon1 from '@/assets/img/media-account/icon-download.png';
|
import icon1 from '@/assets/img/media-account/icon-download.png';
|
||||||
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
||||||
@ -40,6 +39,7 @@ import {
|
|||||||
putMediaAccounts,
|
putMediaAccounts,
|
||||||
getTemplateUrl,
|
getTemplateUrl,
|
||||||
batchMediaAccounts,
|
batchMediaAccounts,
|
||||||
|
getProjectList,
|
||||||
} from '@/api/all/propertyMarketing';
|
} from '@/api/all/propertyMarketing';
|
||||||
|
|
||||||
const UploadStatus = {
|
const UploadStatus = {
|
||||||
@ -54,6 +54,7 @@ const INITIAL_FORM = {
|
|||||||
platform: 1,
|
platform: 1,
|
||||||
group_id: undefined,
|
group_id: undefined,
|
||||||
tag_ids: [],
|
tag_ids: [],
|
||||||
|
project_ids: [],
|
||||||
end_work_link: undefined,
|
end_work_link: undefined,
|
||||||
cookie: undefined,
|
cookie: undefined,
|
||||||
};
|
};
|
||||||
@ -62,6 +63,7 @@ export default {
|
|||||||
setup(props, { emit, expose }) {
|
setup(props, { emit, expose }) {
|
||||||
const groupOptions = ref([]);
|
const groupOptions = ref([]);
|
||||||
const tagOptions = ref([]);
|
const tagOptions = ref([]);
|
||||||
|
const projects = ref([]);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const uploadType = ref('manual');
|
const uploadType = ref('manual');
|
||||||
const uploadStatus = ref(UploadStatus.DEFAULT);
|
const uploadStatus = ref(UploadStatus.DEFAULT);
|
||||||
@ -74,7 +76,7 @@ export default {
|
|||||||
const importPromptModalRef = ref(null);
|
const importPromptModalRef = ref(null);
|
||||||
const uploadRef = ref(null);
|
const uploadRef = ref(null);
|
||||||
const isCustomCookie = ref(false);
|
const isCustomCookie = ref(false);
|
||||||
const form = ref({ ...INITIAL_FORM });
|
const form = ref(cloneDeep(INITIAL_FORM));
|
||||||
const syncDataModalRef = ref(null);
|
const syncDataModalRef = ref(null);
|
||||||
const importLoading = ref(false);
|
const importLoading = ref(false);
|
||||||
const CustomNotificationVisible = ref(false);
|
const CustomNotificationVisible = ref(false);
|
||||||
@ -123,6 +125,12 @@ export default {
|
|||||||
tagOptions.value = data;
|
tagOptions.value = data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const getProjects = async () => {
|
||||||
|
const { code, data } = await getProjectList();
|
||||||
|
if (code === 200) {
|
||||||
|
projects.value = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
function handleUpload(option) {
|
function handleUpload(option) {
|
||||||
const { fileItem } = option;
|
const { fileItem } = option;
|
||||||
uploadStatus.value = UploadStatus.WAITING;
|
uploadStatus.value = UploadStatus.WAITING;
|
||||||
@ -137,7 +145,10 @@ export default {
|
|||||||
const reset = () => {
|
const reset = () => {
|
||||||
formRef.value?.resetFields();
|
formRef.value?.resetFields();
|
||||||
formRef.value?.clearValidate();
|
formRef.value?.clearValidate();
|
||||||
form.value = { ...INITIAL_FORM };
|
groupOptions.value = [];
|
||||||
|
tagOptions.value = [];
|
||||||
|
projects.value = [];
|
||||||
|
form.value = cloneDeep(INITIAL_FORM);
|
||||||
fileName.value = '';
|
fileName.value = '';
|
||||||
file.value = null;
|
file.value = null;
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
@ -158,6 +169,7 @@ export default {
|
|||||||
}
|
}
|
||||||
getGroups();
|
getGroups();
|
||||||
getTags();
|
getTags();
|
||||||
|
getProjects();
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
};
|
};
|
||||||
const getAccountDetail = async () => {
|
const getAccountDetail = async () => {
|
||||||
@ -388,8 +400,16 @@ export default {
|
|||||||
<FormItem label="号码持有人" field="holder_name">
|
<FormItem label="号码持有人" field="holder_name">
|
||||||
<Input v-model={form.value.holder_name} placeholder="请输入..." class="w-240px" size="large" />
|
<Input v-model={form.value.holder_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
<FormItem label="所属项目">
|
||||||
|
<CommonSelect
|
||||||
|
v-model={form.value.project_ids}
|
||||||
|
options={projects.value}
|
||||||
|
placeholder="请选择…"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
<FormItem label="选择分组">
|
<FormItem label="选择分组">
|
||||||
<GroupSelect
|
<CommonSelect
|
||||||
v-model={form.value.group_id}
|
v-model={form.value.group_id}
|
||||||
multiple={false}
|
multiple={false}
|
||||||
options={groupOptions.value}
|
options={groupOptions.value}
|
||||||
@ -397,8 +417,9 @@ export default {
|
|||||||
size="large"
|
size="large"
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem label="选择标签">
|
<FormItem label="选择标签">
|
||||||
<TagSelect v-model={form.value.tag_ids} options={tagOptions.value} placeholder="请选择…" size="large" />
|
<CommonSelect v-model={form.value.tag_ids} options={tagOptions.value} placeholder="请选择…" size="large" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem
|
<FormItem
|
||||||
label="笔记链接"
|
label="笔记链接"
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
<a-form-item label="选择分组" required>
|
<a-form-item label="选择分组" required>
|
||||||
<template v-if="editType === 'all'">
|
<template v-if="editType === 'all'">
|
||||||
<div class="flex items-center w-100%">
|
<div class="flex items-center w-100%">
|
||||||
<GroupSelect v-model="form.group_id" :options="groupOptions" :multiple="false" class="flex-1" />
|
<CommonSelect v-model="form.group_id" :options="groupOptions" :multiple="false" class="flex-1" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<a-table-column title="选择分组" data-index="group_id">
|
<a-table-column title="选择分组" data-index="group_id">
|
||||||
<template #cell="{ record }">
|
<template #cell="{ record }">
|
||||||
<div class="flex items-center w-100%">
|
<div class="flex items-center w-100%">
|
||||||
<GroupSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
|
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-table-column>
|
</a-table-column>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
import { fetchAccountGroups, batchPutGroup } from '@/api/all/propertyMarketing';
|
import { fetchAccountGroups, batchPutGroup } from '@/api/all/propertyMarketing';
|
||||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
import icon1 from '@/assets/img/icon-question.png';
|
import icon1 from '@/assets/img/icon-question.png';
|
||||||
|
|
||||||
|
|||||||
@ -33,16 +33,20 @@
|
|||||||
<span class="label">平台</span>
|
<span class="label">平台</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<a-select v-model="query.platform" size="medium" placeholder="全部" allow-clear @change="handleSearch">
|
<a-select v-model="query.platform" size="medium" placeholder="全部" allow-clear @change="handleSearch">
|
||||||
<a-option v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS" :key="index" :value="item.value" :label="item.label">{{
|
<a-option
|
||||||
item.label
|
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
|
||||||
}}</a-option>
|
:key="index"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
>{{ item.label }}</a-option
|
||||||
|
>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -50,16 +54,22 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">分组</span>
|
<span class="label">分组</span>
|
||||||
<a-space class="w-200px">
|
<a-space class="w-200px">
|
||||||
<GroupSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
<div class="filter-row-item flex items-center">
|
||||||
|
<span class="label">所属项目</span>
|
||||||
|
<a-space class="w-200px">
|
||||||
|
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">标签</span>
|
<span class="label">标签</span>
|
||||||
<a-space class="w-320px">
|
<a-space class="w-320px">
|
||||||
<TagSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" />
|
<CommonSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-search />
|
<icon-search />
|
||||||
</template>
|
</template>
|
||||||
@ -77,11 +87,14 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, defineEmits, defineProps } from 'vue';
|
import { reactive, defineEmits, defineProps } from 'vue';
|
||||||
import { fetchAccountTags, fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
import {
|
||||||
import TagSelect from '@/views/property-marketing/media-account/components/tag-select';
|
fetchAccountTags,
|
||||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
getProjectList,
|
||||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select';
|
fetchAccountGroups,
|
||||||
|
fetchAccountOperators,
|
||||||
|
} from '@/api/all/propertyMarketing';
|
||||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||||
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
import { INITIAL_QUERY } from '@/views/property-marketing/media-account/account-manage/constants';
|
import { INITIAL_QUERY } from '@/views/property-marketing/media-account/account-manage/constants';
|
||||||
import { MEDIA_ACCOUNT_PLATFORMS } from '@/utils/platform';
|
import { MEDIA_ACCOUNT_PLATFORMS } from '@/utils/platform';
|
||||||
@ -98,6 +111,7 @@ const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
|||||||
const tags = ref([]);
|
const tags = ref([]);
|
||||||
const groups = ref([]);
|
const groups = ref([]);
|
||||||
const operators = ref([]);
|
const operators = ref([]);
|
||||||
|
const projects = ref([]);
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
emits('update:query', props.query);
|
emits('update:query', props.query);
|
||||||
@ -128,11 +142,18 @@ const getOperators = async () => {
|
|||||||
operators.value = data;
|
operators.value = data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const getProjects = async () => {
|
||||||
|
const { code, data } = await getProjectList();
|
||||||
|
if (code === 200) {
|
||||||
|
projects.value = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTags();
|
getTags();
|
||||||
getGroups();
|
getGroups();
|
||||||
getOperators();
|
getOperators();
|
||||||
|
getProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export const INITIAL_QUERY = {
|
|||||||
operator_id: '',
|
operator_id: '',
|
||||||
group_ids: [],
|
group_ids: [],
|
||||||
tag_ids: [],
|
tag_ids: [],
|
||||||
|
project_ids: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const INITIAL_PAGE_INFO = {
|
export const INITIAL_PAGE_INFO = {
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
<!--
|
|
||||||
* @Author: RenXiaoDong
|
|
||||||
* @Date: 2025-06-25 14:02:40
|
|
||||||
-->
|
|
||||||
<template>
|
|
||||||
<a-select
|
|
||||||
v-model="selectedOperators"
|
|
||||||
:multiple="multiple"
|
|
||||||
size="medium"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
allow-clear
|
|
||||||
@change="handleChange"
|
|
||||||
>
|
|
||||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
|
||||||
{{ item.name }}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: [Array, String, Number],
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
multiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: '全部',
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue', 'change']);
|
|
||||||
|
|
||||||
const selectedOperators = ref(props.multiple ? [] : '');
|
|
||||||
|
|
||||||
// 监听外部传入的值变化
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newVal) => {
|
|
||||||
selectedOperators.value = newVal;
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
// 监听内部值变化,向外部发送更新
|
|
||||||
watch(selectedOperators, (newVal) => {
|
|
||||||
emits('update:modelValue', newVal);
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (value) => {
|
|
||||||
selectedOperators.value = value;
|
|
||||||
emits('change', value);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<OperatorSelect v-model="query.operator_id" :options="operators" />
|
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -80,7 +80,7 @@ import {
|
|||||||
getPlacementAccountProjectsTrend,
|
getPlacementAccountProjectsTrend,
|
||||||
fetchAccountOperators,
|
fetchAccountOperators,
|
||||||
} from '@/api/all/propertyMarketing';
|
} from '@/api/all/propertyMarketing';
|
||||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select/index.vue';
|
import CommonSelect from '@/components/common-select';
|
||||||
import AccountSelect from '@/views/components/common/AccountSelect.vue';
|
import AccountSelect from '@/views/components/common/AccountSelect.vue';
|
||||||
import PlanSelect from '@/views/components/common/PlanSelect.vue';
|
import PlanSelect from '@/views/components/common/PlanSelect.vue';
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<div v-if="!isAccountTab" class="filter-row-item flex items-center">
|
<div v-if="!isAccountTab" class="filter-row-item flex items-center">
|
||||||
<span class="label">计划分组</span>
|
<span class="label">计划分组</span>
|
||||||
<a-space class="w-200px">
|
<a-space class="w-200px">
|
||||||
<group-select v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -78,9 +78,8 @@ import {
|
|||||||
getPlacementAccountsList,
|
getPlacementAccountsList,
|
||||||
getPlacementAccountOperators,
|
getPlacementAccountOperators,
|
||||||
} from '@/api/all/propertyMarketing';
|
} from '@/api/all/propertyMarketing';
|
||||||
import GroupSelect from '../group-select';
|
|
||||||
|
|
||||||
import OperatorSelect from '@/views/property-marketing/put-account/components/operator-select';
|
import CommonSelect from '@/components/common-select';
|
||||||
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
||||||
import AccountSelect from '@/views/property-marketing/put-account/components/account-select';
|
import AccountSelect from '@/views/property-marketing/put-account/components/account-select';
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,30 @@
|
|||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<span class="cts">{{ item.operator?.name }}</span>
|
<span class="cts">{{ item.operator?.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<span class="label">所属项目</span>
|
||||||
|
<span v-if="!item.projects.length" class="cts">-</span>
|
||||||
|
<div v-else class="flex items-center">
|
||||||
|
<a-tooltip
|
||||||
|
v-if="item.projects.length > 2"
|
||||||
|
position="bottom"
|
||||||
|
:content="
|
||||||
|
item.projects
|
||||||
|
.slice(2)
|
||||||
|
.map((v) => v.name)
|
||||||
|
.join(',')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="tag-box">
|
||||||
|
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<div v-for="(project, index) in item.projects.slice(0, 2)" :key="index" class="tag-box">
|
||||||
|
<span class="text">{{ project.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="field-row">
|
<div class="field-row">
|
||||||
<span class="label">账户总消耗</span>
|
<span class="label">账户总消耗</span>
|
||||||
<span class="cts">{{ `¥${formatNumberShow({ value: item.total_use_amount, showExactValue: true })}` }}</span>
|
<span class="cts">{{ `¥${formatNumberShow({ value: item.total_use_amount, showExactValue: true })}` }}</span>
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
@mixin ellipsis {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container {
|
.card-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -111,6 +111,9 @@
|
|||||||
</a-radio>
|
</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="所属项目" field="project_ids">
|
||||||
|
<CommonSelect v-model="form.project_ids" :options="projects" placeholder="请选择…" size="large" />
|
||||||
|
</a-form-item>
|
||||||
<template v-if="isEdit">
|
<template v-if="isEdit">
|
||||||
<a-form-item label="账户总消耗" field="total_use_amount">
|
<a-form-item label="账户总消耗" field="total_use_amount">
|
||||||
<a-input v-model="form.total_use_amount" placeholder="请输入..." size="large" disabled />
|
<a-input v-model="form.total_use_amount" placeholder="请输入..." size="large" disabled />
|
||||||
@ -148,6 +151,8 @@ import { ref, defineEmits } from 'vue';
|
|||||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||||
// import ImportPromptModal from '../import-prompt-modal';
|
// import ImportPromptModal from '../import-prompt-modal';
|
||||||
import StatusBox from '../status-box';
|
import StatusBox from '../status-box';
|
||||||
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
import { PLATFORM_LIST, ENUM_PUT_ACCOUNT_PLATFORM } from '@/utils/platform';
|
import { PLATFORM_LIST, ENUM_PUT_ACCOUNT_PLATFORM } from '@/utils/platform';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -156,6 +161,7 @@ import {
|
|||||||
putPlacementAccounts,
|
putPlacementAccounts,
|
||||||
getPlacementAccountsTemplateUrl,
|
getPlacementAccountsTemplateUrl,
|
||||||
batchPlacementAccounts,
|
batchPlacementAccounts,
|
||||||
|
getProjectList,
|
||||||
} from '@/api/all/propertyMarketing';
|
} from '@/api/all/propertyMarketing';
|
||||||
|
|
||||||
import icon1 from '@/assets/img/media-account/icon-download.png';
|
import icon1 from '@/assets/img/media-account/icon-download.png';
|
||||||
@ -174,6 +180,7 @@ const INITIAL_FORM = {
|
|||||||
holder_name: '',
|
holder_name: '',
|
||||||
platform: 0,
|
platform: 0,
|
||||||
is_sync_project: 1,
|
is_sync_project: 1,
|
||||||
|
project_ids: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
@ -188,6 +195,7 @@ const authorizedAccountModalRef = ref(null);
|
|||||||
const uploadRef = ref(null);
|
const uploadRef = ref(null);
|
||||||
const file = ref(null);
|
const file = ref(null);
|
||||||
const form = ref(cloneDeep(INITIAL_FORM));
|
const form = ref(cloneDeep(INITIAL_FORM));
|
||||||
|
const projects = ref([]);
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
mobile: [
|
mobile: [
|
||||||
@ -240,6 +248,7 @@ const reset = () => {
|
|||||||
fileName.value = '';
|
fileName.value = '';
|
||||||
file.value = null;
|
file.value = null;
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
|
projects.value = [];
|
||||||
uploadStatus.value = UploadStatus.DEFAULT;
|
uploadStatus.value = UploadStatus.DEFAULT;
|
||||||
uploadType.value = 'manual';
|
uploadType.value = 'manual';
|
||||||
};
|
};
|
||||||
@ -252,12 +261,19 @@ const open = (accountId = '') => {
|
|||||||
id.value = accountId;
|
id.value = accountId;
|
||||||
isEdit.value = !!accountId;
|
isEdit.value = !!accountId;
|
||||||
|
|
||||||
|
getProjects();
|
||||||
if (accountId) {
|
if (accountId) {
|
||||||
getAccountDetail();
|
getAccountDetail();
|
||||||
}
|
}
|
||||||
|
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
};
|
};
|
||||||
|
const getProjects = async () => {
|
||||||
|
const { code, data } = await getProjectList();
|
||||||
|
if (code === 200) {
|
||||||
|
projects.value = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getAccountDetail = async () => {
|
const getAccountDetail = async () => {
|
||||||
const { code, data } = await getPlacementAccountsDetail(id.value);
|
const { code, data } = await getPlacementAccountsDetail(id.value);
|
||||||
|
|||||||
@ -42,11 +42,17 @@
|
|||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<span class="label">运营人员</span>
|
<span class="label">运营人员</span>
|
||||||
<a-space class="w-160px">
|
<a-space class="w-160px">
|
||||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-row flex">
|
<div class="filter-row flex">
|
||||||
|
<div class="filter-row-item flex items-center">
|
||||||
|
<span class="label">所属项目</span>
|
||||||
|
<a-space class="w-200px">
|
||||||
|
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" />
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-search />
|
<icon-search />
|
||||||
@ -65,10 +71,10 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineEmits, defineProps } from 'vue';
|
import { defineEmits, defineProps } from 'vue';
|
||||||
import { getPlacementAccountOperators } from '@/api/all/propertyMarketing';
|
import { getPlacementAccountOperators, getProjectList } from '@/api/all/propertyMarketing';
|
||||||
import { PLATFORM_LIST } from '@/utils/platform';
|
import { PLATFORM_LIST } from '@/utils/platform';
|
||||||
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
||||||
import OperatorSelect from '@/views/property-marketing/put-account/components/operator-select';
|
import CommonSelect from '@/components/common-select';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
query: {
|
query: {
|
||||||
@ -80,6 +86,7 @@ const props = defineProps({
|
|||||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||||
|
|
||||||
const operators = ref([]);
|
const operators = ref([]);
|
||||||
|
const projects = ref([]);
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
emits('update:query', props.query);
|
emits('update:query', props.query);
|
||||||
@ -97,9 +104,16 @@ const getOperators = async () => {
|
|||||||
operators.value = data;
|
operators.value = data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const getProjects = async () => {
|
||||||
|
const { code, data } = await getProjectList();
|
||||||
|
if (code === 200) {
|
||||||
|
projects.value = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getOperators();
|
getOperators();
|
||||||
|
getProjects();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -8,4 +8,5 @@ export const INITIAL_QUERY = {
|
|||||||
status: '',
|
status: '',
|
||||||
platform: '',
|
platform: '',
|
||||||
operator_id: '',
|
operator_id: '',
|
||||||
|
project_ids: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
<!--
|
|
||||||
* @Author: RenXiaoDong
|
|
||||||
* @Date: 2025-06-25 14:02:40
|
|
||||||
-->
|
|
||||||
<template>
|
|
||||||
<a-select
|
|
||||||
v-model="selectedOperators"
|
|
||||||
:multiple="multiple"
|
|
||||||
size="medium"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
allow-clear
|
|
||||||
@change="handleChange"
|
|
||||||
>
|
|
||||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
|
||||||
{{ item.name }}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: [Array, String, Number],
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
multiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: '全部',
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue', 'change']);
|
|
||||||
|
|
||||||
const selectedOperators = ref(props.multiple ? [] : '');
|
|
||||||
|
|
||||||
// 监听外部传入的值变化
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newVal) => {
|
|
||||||
selectedOperators.value = newVal;
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
// 监听内部值变化,向外部发送更新
|
|
||||||
watch(selectedOperators, (newVal) => {
|
|
||||||
emits('update:modelValue', newVal);
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (value) => {
|
|
||||||
selectedOperators.value = value;
|
|
||||||
emits('change', value);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
Reference in New Issue
Block a user