Merge remote-tracking branch 'origin/feature/v1.3_营销资产中台' into feature/v1.3_营销资产中台

This commit is contained in:
林志军
2025-07-10 14:24:11 +08:00
35 changed files with 525 additions and 252 deletions

View File

@ -225,7 +225,6 @@ const clearError = (field: string) => {
const handleOk = async () => {
visible.value = false;
await enterpriseStore.updateEnterpriseInfo();
handleUserLogin();
};
@ -269,11 +268,9 @@ const getProfileInfo = async () => {
mobileNumber.value = data['mobile'];
accounts.value = enterprises;
enterpriseStore.setEnterpriseInfo(data);
userStore.setUserInfo(data);
if (enterprises.length > 0) {
if (enterprises.length === 1) {
await enterpriseStore.updateEnterpriseInfo();
handleUserLogin();
} else {
// 多个企业时候需要弹窗让用户选择企业

View File

@ -99,7 +99,7 @@ const addAccountVisible = ref(false);
const deleteVisible = ref(false);
const deleteTitle = ref('');
const enterpriseInfo = store.getEnterpriseInfo();
const enterpriseInfo = store.enterpriseInfo;
const okText = computed(() => {
if (!canAddAccount.value) {

View File

@ -48,7 +48,7 @@ const form = reactive({
name: '',
});
const enterpriseInfo = store.getEnterpriseInfo();
const enterpriseInfo = store.enterpriseInfo;
const columns = [
{

View File

@ -26,7 +26,7 @@
v-if="props.product.status === Status.Enable || props.product.status === Status.ON_TRIAL"
class="primary-button"
type="primary"
@click="gotoModule(props.product.menu_id)"
@click="gotoModule(props.product.id)"
>
进入模块
</a-button>
@ -70,13 +70,16 @@ import { trialProduct } from '@/api/all';
import { useRouter } from 'vue-router';
import CustomerServiceModal from '@/components/customer-service-modal.vue';
import { appRoutes } from '@/router/routes';
import { useSidebarStore } from '@/stores/modules/side-bar';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import { useUserStore } from '@/stores';
import { getUserEnterpriseInfo } from '@/utils/user';
const props = defineProps<{
product: Product;
}>();
const emit = defineEmits(['refresh']);
const sidebarStore = useSidebarStore();
enum Status {
Disable = 0, // 禁用
@ -87,30 +90,37 @@ enum Status {
}
interface Product {
id: number;
status: Status;
name: string;
image: string;
desc: string;
menu_id: number;
id: number;
expired_at?: number;
}
const visible = ref(false);
const router = useRouter();
const enterpriseStore = useEnterpriseStore();
const userStore = useUserStore();
const sidebarStore = useSidebarStore();
const handleTrial = async (id: any) => {
await trialProduct(id);
AMessage.success('试用成功!');
emit('refresh');
const { code } = await trialProduct(id);
if (code === 200) {
getUserEnterpriseInfo();
AMessage.success('试用成功!');
emit('refresh');
}
};
const gotoModule = (menuId: number) => {
const _target = appRoutes.find((v) => v.meta.id === menuId);
if (_target) {
console.log({ _target });
router.push({ name: _target.name });
}
const routeMap: Record<number, string> = {
'1': 'DataEngineHotTranslation',
'2': 'RepositoryBrandMaterials',
};
console.log(routeMap[menuId]);
router.push({ name: routeMap[menuId] });
};
</script>
<style scoped lang="less">

View File

@ -87,15 +87,12 @@
</a-form-item>
</template>
<a-form-item label="手机号" field="mobile" required>
<a-form-item label="手机号" field="mobile" required>
<a-input v-model="form.mobile" placeholder="请输入..." size="large" />
</a-form-item>
<a-form-item label="运营人员" field="operator_name" required>
<a-input v-model="form.operator_name" placeholder="请输入..." class="w-240px" size="large" />
</a-form-item>
<a-form-item label="号码持有人" field="holder_name" required>
<a-input v-model="form.holder_name" placeholder="请输入..." class="w-240px" size="large" />
</a-form-item>
<a-form-item label="运营平台" :required="!isEdit">
<img v-if="isEdit" :src="form.platform === 0 ? icon3 : icon4" width="24" height="24" />
<a-radio-group v-else v-model="form.platform">
@ -103,6 +100,9 @@
<a-radio :value="1">小红书</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="号码持有人" field="holder_name">
<a-input v-model="form.holder_name" placeholder="请输入..." class="w-240px" size="large" />
</a-form-item>
<a-form-item label="选择分组">
<GroupSelect
v-model="form.group_id"
@ -130,6 +130,26 @@
:auto-size="{ minRows: 3, maxRows: 5 }"
/>
</a-form-item>
<template v-if="!isEdit">
<a-form-item label="Cookie值">
<template #label>
<span class="label">Cookie值</span>
<a-tooltip content="开启后可直接填写 Cookie无需扫码授权">
<icon-question-circle size="14" class="ml-4px color-#737478" />
</a-tooltip>
</template>
<a-switch v-model="isCustomCookie" size="large" />
</a-form-item>
<a-form-item v-if="isCustomCookie" label="" field="cookie">
<a-textarea
v-model="form.cookie"
placeholder="请输入..."
size="large"
max-length="72"
:auto-size="{ minRows: 3, maxRows: 5 }"
/>
</a-form-item>
</template>
</template>
</a-form>
<template #footer>
@ -181,7 +201,8 @@ const INITIAL_FORM = {
platform: 0,
group_id: undefined,
tag_ids: [],
end_work_link: '',
end_work_link: undefined,
cookie: undefined,
};
const groupOptions = ref([]);
@ -197,6 +218,7 @@ const file = ref(null);
const authorizedAccountModalRef = ref(null);
const importPromptModalRef = ref(null);
const uploadRef = ref(null);
const isCustomCookie = ref(false);
const form = ref(cloneDeep(INITIAL_FORM));
const rules = {
@ -218,7 +240,7 @@ const rules = {
},
],
operator_name: [{ required: true, message: '请输入运营人员' }],
holder_name: [{ required: true, message: '请输入号码持有人' }],
// holder_name: [{ required: true, message: '请输入号码持有人' }],
};
const isBatchImport = computed(() => uploadType.value === 'batch');
@ -266,6 +288,7 @@ const reset = () => {
fileName.value = '';
file.value = null;
isEdit.value = false;
isCustomCookie.value = false;
uploadStatus.value = UploadStatus.DEFAULT;
uploadType.value = 'manual';
};
@ -320,6 +343,30 @@ const handleBatchImport = async () => {
}
};
const handleAddAccount = async () => {
const _isCustomCookie = isCustomCookie.value;
const { code, data } = await postMediaAccounts({
...form.value,
cookie: _isCustomCookie ? form.value.cookie : undefined,
});
if (code === 200) {
emits('update');
onClose();
const { id, platform } = data;
!_isCustomCookie && startAuthorized(id, platform);
}
};
const handleEditAccount = async () => {
const { code } = await putMediaAccounts({ id: id.value, ...form.value });
if (code === 200) {
AMessage.success('修改成功');
emits('update');
onClose();
}
};
async function onSubmit() {
if (isBatchImport.value) {
handleBatchImport();
@ -328,17 +375,7 @@ async function onSubmit() {
formRef.value.validate(async (errors) => {
if (!errors) {
const _fn = id.value ? putMediaAccounts : postMediaAccounts;
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');
onClose();
if (!isEdit.value) {
startAuthorized(data?.id, data?.platform);
}
}
isEdit.value ? handleEditAccount() : handleAddAccount();
}
});
}

View File

@ -34,7 +34,7 @@
<div class="img-box">
<template v-if="qrCodeLoading || isFailLoadQrCode">
<div class="relative w-160px h-160px">
<a-image v-if="qrCodeLoading" :src="icon1" width="160" height="160" />
<a-image :src="icon1" width="160" height="160" />
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
<img v-if="isFailLoadQrCode" :src="icon4" width="24" height="24" class="mb-13px" />
<icon-loading v-else size="24" class="color-#6D4CFE mb-13px" />
@ -49,7 +49,7 @@
</template>
<a-image v-else :src="qrCodeUrl" width="160" height="160" />
<div v-if="isOverdue" class="mask cursor-pointer" @click="getAuthorizedQrCode">
<div v-if="isOverdue" class="mask cursor-pointer" @click="handleRefreshQrCode">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
@ -225,11 +225,15 @@ const clearOverdueTimer = () => {
overdueTimer = null;
}
};
// 重新扫码
const handleRefreshQrCode = () => {
resetTaskFields();
getAuthorizedQrCode();
};
const handleOk = () => {
if (isFailLoadQrCode.value) {
resetTaskFields();
getAuthorizedQrCode();
handleRefreshQrCode();
return;
}
@ -249,8 +253,7 @@ const handleOk = () => {
if (isSuccess.value) {
close();
} else {
resetTaskFields();
getAuthorizedQrCode();
handleRefreshQrCode();
}
} else {
startLoading();

View File

@ -34,7 +34,7 @@
<div class="img-box">
<template v-if="qrCodeLoading || isFailLoadQrCode">
<div class="relative w-160px h-160px">
<a-image v-if="qrCodeLoading" :src="icon1" width="160" height="160" />
<a-image :src="icon1" width="160" height="160" />
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
<img v-if="isFailLoadQrCode" :src="icon4" width="24" height="24" class="mb-13px" />
<icon-loading v-else size="24" class="color-#6D4CFE mb-13px" />
@ -49,7 +49,7 @@
</template>
<a-image v-else :src="qrCodeUrl" width="160" height="160" />
<div v-if="isOverdue" class="mask cursor-pointer" @click="getAuthorizedQrCode">
<div v-if="isOverdue" class="mask cursor-pointer" @click="handleRefreshQrCode">
<icon-refresh size="24" class="mb-13px" />
<p class="s1">二维码失效</p>
<p class="s1">请点击刷新</p>
@ -277,11 +277,16 @@ const clearStatusPollingTimer = () => {
}
};
// 重新扫码
const handleRefreshQrCode = () => {
resetTaskFields();
getAuthorizedQrCode();
};
const handleOk = () => {
if (taskStep.value === TASK_STEP.default) {
if (isFailLoadQrCode.value) {
resetTaskFields();
getAuthorizedQrCode();
handleRefreshQrCode();
return;
}
@ -308,8 +313,7 @@ const handleOk = () => {
if (isSuccess.value) {
close();
} else {
resetTaskFields();
getAuthorizedQrCode();
handleRefreshQrCode();
}
}
}