AdwebSiteList.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <template>
  2. <div class="p-2">
  3. <!--查询区域-->
  4. <div class="jeecg-basic-table-form-container">
  5. <a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
  6. <a-row :gutter="24">
  7. <a-col :xxl="6" :xl="7">
  8. <a-form-item name="name" label="站点名称">
  9. <j-input placeholder="请输入站点名称" v-model:value="queryParam.name" allow-clear />
  10. </a-form-item>
  11. </a-col>
  12. <a-col :xxl="6" :xl="7">
  13. <a-form-item name="domain" label="站点域名">
  14. <j-input placeholder="请输入站点域名" v-model:value="queryParam.domain" allow-clear />
  15. </a-form-item>
  16. </a-col>
  17. <a-col :xxl="6" :xl="8">
  18. <a-form-item label="发布状态">
  19. <j-search-select allow-clear placeholder="请选择发布状态" v-model:value="queryParam.status" dict="site_status" />
  20. </a-form-item>
  21. </a-col>
  22. <a-col v-if="isAdmin" :xxl="6" :xl="7">
  23. <a-form-item label="租户">
  24. <j-search-select
  25. allow-clear
  26. placeholder="请选择租户"
  27. v-model:value="queryParam.channelProviderId"
  28. dict="sys_tenant,name,id,del_flag=0 AND status=1"
  29. />
  30. </a-form-item>
  31. </a-col>
  32. <template v-if="toggleSearchStatus">
  33. <!-- <a-col :xxl="12" :xl="10">-->
  34. <!-- <a-form-item label="创建时间">-->
  35. <!-- <j-range-date placeholder="请选择开始日期" class="query-group-cust" v-model:value="queryParam.ctime" />-->
  36. <!-- </a-form-item>-->
  37. <!-- </a-col>-->
  38. <!-- <a-col :xl="10" :lg="11" :md="12" :sm="24">-->
  39. <!-- <a-form-item label="到期时间">-->
  40. <!-- <j-range-date placeholder="请选择开始日期" class="query-group-cust" v-model:value="queryParam.etime" />-->
  41. <!-- </a-form-item>-->
  42. <!-- </a-col>-->
  43. </template>
  44. <a-col :xl="6" :lg="7" :md="8" :sm="24">
  45. <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
  46. <a-col :lg="6">
  47. <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
  48. <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
  49. <a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
  50. {{ toggleSearchStatus ? '收起' : '展开' }}
  51. <Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
  52. </a>
  53. </a-col>
  54. </span>
  55. </a-col>
  56. </a-row>
  57. </a-form>
  58. </div>
  59. <!--引用表格-->
  60. <BasicTable @register="registerTable" :rowSelection="rowSelection">
  61. <!--插槽:table标题-->
  62. <template #tableTitle>
  63. <!-- <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>-->
  64. <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
  65. <!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>-->
  66. <!-- <a-dropdown v-if="selectedRowKeys.length > 0">-->
  67. <!-- <template #overlay>-->
  68. <!-- <a-menu>-->
  69. <!-- <a-menu-item key="1" @click="batchHandleDelete">-->
  70. <!-- <Icon icon="ant-design:delete-outlined" />-->
  71. <!-- 删除-->
  72. <!-- </a-menu-item>-->
  73. <!-- </a-menu>-->
  74. <!-- </template>-->
  75. <!-- <a-button-->
  76. <!-- >批量操作-->
  77. <!-- <Icon icon="mdi:chevron-down" />-->
  78. <!-- </a-button>-->
  79. <!-- </a-dropdown>-->
  80. <!-- 高级查询 -->
  81. <super-query :config="superQueryConfig" @search="handleSuperQuery" />
  82. </template>
  83. <!--操作栏-->
  84. <template #action="{ record }">
  85. <TableAction
  86. style="padding: 5px 8px; display: flex; justify-content: space-around"
  87. :actions="getTableAction(record)"
  88. :dropDownActions="getDropDownAction(record)"
  89. />
  90. </template>
  91. <template #bodyCell="{ column, record, index, text }">
  92. <div v-if="column.dataIndex == 'name'">
  93. <a :href="record.domain" target="_blank">{{ text }}</a>
  94. </div>
  95. <div v-if="column.dataIndex == 'domain'">
  96. <a :href="record.domain" target="_blank">{{ text }}</a>
  97. </div>
  98. <div v-if="column.dataIndex == 'subscribePlan'">
  99. <template v-if="text === null || text === ''"> 无 </template>
  100. <template v-else>
  101. <a-popover>
  102. <template #content>
  103. <a-descriptions bordered :column="{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }" title="SEO套餐详情" size="default">
  104. <a-descriptions-item label="套餐名">
  105. {{ text.planName }}
  106. </a-descriptions-item>
  107. <a-descriptions-item label="关键词"> {{ text.keywordCount }}个 </a-descriptions-item>
  108. <a-descriptions-item label="服务时间">
  109. <template v-if="text.serviceTime != 0"> {{ text.serviceTime }}个月 </template>
  110. <template v-else> 长期 </template>
  111. </a-descriptions-item>
  112. <a-descriptions-item label="价格"> {{ text.price }}元 </a-descriptions-item>
  113. </a-descriptions>
  114. </template>
  115. <a-tag color="blue">
  116. {{ text.planName }}
  117. </a-tag>
  118. </a-popover>
  119. </template>
  120. </div>
  121. <div v-if="column.dataIndex == 'status_dictText'">
  122. <template v-if="record.status == 1">
  123. <a-tag color="blue">
  124. {{ text }}
  125. </a-tag>
  126. </template>
  127. <template v-else-if="record.status == 2">
  128. <a-tag color="green">
  129. {{ text }}
  130. </a-tag>
  131. </template>
  132. <template v-else>
  133. <a-tag color="red">
  134. {{ text }}
  135. </a-tag>
  136. </template>
  137. </div>
  138. <div v-if="column.dataIndex == 'siteCurrentStep'">
  139. <span v-if="text === null || text === undefined || text === ''"> - </span>
  140. <template v-else>
  141. <a @click="handleProcess(record, 'site')"> <span class="circle" style="background-color: #7194f8"></span>{{ text }} </a>
  142. </template>
  143. </div>
  144. <div v-if="column.dataIndex == 'completeProcess'">
  145. <a-progress :stroke-color="{ '0%': '#108ee9', '100%': '#87d068' }" :percent="record.completeProcess" />
  146. </div>
  147. </template>
  148. </BasicTable>
  149. <!-- 表单区域 -->
  150. <AdwebSiteModal ref="registerModal" @success="handleSuccess" />
  151. <site-set-enquiry ref="siteSetEnquiryRef" @success="reload" />
  152. <!-- 自动化嵌入GTM 代码 -->
  153. <gtm-add ref="gtmRef" />
  154. <!--SEO流程-->
  155. <seo-process ref="seoProcessRef" :visible="seoProcessVisible" :title="processTitle" @close="closeProcess" @reload="reload" />
  156. <google-ads-modal ref="googleAdsModalRef" @success="reload" />
  157. <Sohoeb2bOrder ref="sohoeb2bOrderRef" @reload="reload" />
  158. <SiteRelease ref="siteReleaseRef" @reload="reload" />
  159. </div>
  160. </template>
  161. <script lang="ts" name="adweb-adwebSite" setup>
  162. import { computed, onBeforeMount, reactive, ref } from 'vue';
  163. import { BasicTable, TableAction } from '/src/components/Table';
  164. import { useListPage } from '/src/hooks/system/useListPage';
  165. import { columns, superQuerySchema } from './AdwebSite.data';
  166. import { batchDelete, deleteOne, getExportUrl, getImportUrl, list, saveOrUpdate } from './AdwebSite.api';
  167. import AdwebSiteModal from './components/AdwebSiteModal.vue';
  168. import { useUserStore } from '/src/store/modules/user';
  169. import SeoProcess from '@/views/adweb/site/components/SeoProcess.vue';
  170. import JInput from '@/components/Form/src/jeecg/components/JInput.vue';
  171. import JSearchSelect from '@/components/Form/src/jeecg/components/JSearchSelect.vue';
  172. import GtmAdd from '@/views/adweb/site/components/GtmAdd.vue';
  173. import { RoleEnum } from '@/enums/roleEnum';
  174. import { useMessage } from '@/hooks/web/useMessage';
  175. import SiteSetEnquiry from '@/views/adweb/site/components/SiteSetEnquiry.vue';
  176. import GoogleAdsModal from './components/GoogleAdsModal.vue';
  177. import { getAuthCache } from '@/utils/auth';
  178. import { TENANT_ID } from '@/enums/cacheEnum';
  179. import { getTenantById } from '@/views/system/tenant/tenant.api';
  180. import Sohoeb2bOrder from '@/views/adweb/site/components/Sohoeb2bOrder.vue';
  181. import SiteRelease from '@/views/adweb/site/components/SiteRelease.vue';
  182. const formRef = ref();
  183. const queryParam = reactive<any>({});
  184. const toggleSearchStatus = ref<boolean>(false);
  185. const registerModal = ref();
  186. const userStore = useUserStore();
  187. const processTitle = ref('');
  188. const seoProcessVisible = ref(false);
  189. const seoProcessRef = ref();
  190. const sohoeb2bOrderRef = ref();
  191. const siteReleaseRef = ref();
  192. const gtmRef = ref();
  193. const siteSetEnquiryRef = ref();
  194. const googleAdsModalRef = ref();
  195. // admin 判断和后端保持一致
  196. // src/main/java/org/jeecg/modules/adweb/system/service/impl/SysAdwebApiImpl.java L60
  197. // TODO 将此判断加入store,方便所有组件全局调用
  198. console.log(userStore.getRoleList, '当前用户所属角色');
  199. const isAdmin = computed(() => {
  200. return (
  201. userStore.getRoleList.includes(RoleEnum.ADMIN) ||
  202. userStore.getRoleList.includes(RoleEnum.ADWEB_ADMIN) ||
  203. userStore.getRoleList.includes(RoleEnum.SEO_ADMIN) ||
  204. userStore.getRoleList.includes(RoleEnum.ADWEB_SITE_MANAGER) ||
  205. userStore.getRoleList.includes(RoleEnum.ADWEB_SEO_MANAGER)
  206. );
  207. });
  208. // 租户管理员角色
  209. const isTenantAdmin = computed(() => {
  210. return userStore.getRoleList.includes(RoleEnum.ADWEB_CHANNEL_ADMIN);
  211. });
  212. // 是否是苏豪纺织的租户
  213. const isSohoeb2b = ref(false);
  214. const { createMessage } = useMessage();
  215. //注册table数据
  216. const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
  217. tableProps: {
  218. title: 'adweb站点配置表单',
  219. api: list,
  220. columns,
  221. canResize: false,
  222. useSearchForm: true,
  223. showTableSetting: true,
  224. actionColumn: {
  225. width: 180,
  226. fixed: 'right',
  227. },
  228. beforeFetch: (params) => {
  229. return Object.assign(params, queryParam);
  230. },
  231. },
  232. exportConfig: {
  233. name: 'adweb站点配置表单',
  234. url: getExportUrl,
  235. params: queryParam,
  236. },
  237. importConfig: {
  238. url: getImportUrl,
  239. success: handleSuccess,
  240. },
  241. });
  242. const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
  243. tableContext;
  244. const labelCol = reactive({
  245. xs: 24,
  246. sm: 4,
  247. xl: 6,
  248. xxl: 4,
  249. });
  250. const wrapperCol = reactive({
  251. xs: 24,
  252. sm: 20,
  253. });
  254. // 高级查询配置
  255. const superQueryConfig = reactive(superQuerySchema);
  256. onBeforeMount(async () => {
  257. isSohoeb2bTenant();
  258. });
  259. /**
  260. * 高级查询事件
  261. */
  262. function handleSuperQuery(params) {
  263. Object.keys(params).map((k) => {
  264. queryParam[k] = params[k];
  265. });
  266. searchQuery();
  267. }
  268. /**
  269. * 新增事件
  270. */
  271. function handleAdd() {
  272. registerModal.value.disableSubmit = false;
  273. registerModal.value.add();
  274. }
  275. /**
  276. * 编辑事件
  277. */
  278. function handleEdit(record: Recordable) {
  279. registerModal.value.disableSubmit = false;
  280. registerModal.value.edit(record);
  281. }
  282. /**
  283. * 详情
  284. */
  285. function handleDetail(record: Recordable) {
  286. registerModal.value.disableSubmit = true;
  287. registerModal.value.edit(record);
  288. }
  289. /**
  290. * 删除事件
  291. */
  292. async function handleDelete(record) {
  293. await deleteOne({ id: record.id }, handleSuccess);
  294. }
  295. async function siteDeleteStatus(record) {
  296. record.status = 0;
  297. await saveOrUpdate(record, true)
  298. .then((res) => {
  299. if (res.success) {
  300. createMessage.success(res.message);
  301. } else {
  302. createMessage.warning(res.message);
  303. }
  304. reload();
  305. })
  306. .finally(() => {});
  307. }
  308. function isSohoeb2bTenant() {
  309. getTenantById({ id: getAuthCache(TENANT_ID) }).then((res) => {
  310. isSohoeb2b.value = res.name.includes('苏豪纺织集团');
  311. });
  312. }
  313. /**
  314. * 批量删除事件
  315. */
  316. async function batchHandleDelete() {
  317. await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  318. }
  319. /**
  320. * 成功回调
  321. */
  322. function handleSuccess() {
  323. (selectedRowKeys.value = []) && reload();
  324. }
  325. /**
  326. * 操作栏
  327. */
  328. function getTableAction(record) {
  329. return [
  330. {
  331. label: '编辑网站',
  332. onClick: handleEdit.bind(null, record),
  333. },
  334. ];
  335. }
  336. /**
  337. * 下拉操作栏
  338. */
  339. function getDropDownAction(record) {
  340. let dropDown = [
  341. // {
  342. // label: '详情',
  343. // onClick: handleDetail.bind(null, record),
  344. // },
  345. ];
  346. // 站点不是删除状态
  347. if (record.status === 2) {
  348. dropDown.push({
  349. label: '发布上线',
  350. onClick: wpSiteRelease.bind(null, record),
  351. });
  352. }
  353. // 针对苏豪纺织租户管理员,或者是管理员
  354. if ((isTenantAdmin.value && isSohoeb2b.value) || isAdmin.value) {
  355. dropDown.push({
  356. label: '订单设置',
  357. onClick: setSohoeb2bOrder.bind(null, record),
  358. });
  359. }
  360. dropDown.push({
  361. label: '询盘设置',
  362. onClick: setEnquiry.bind(null, record),
  363. });
  364. // 站点不是删除状态
  365. if (record.status != 0) {
  366. dropDown.push({
  367. label: '站点删除',
  368. onClick: siteDeleteStatus.bind(null, record),
  369. });
  370. }
  371. // 站点已发布,并且是正式域名时可以添加GTM 代码
  372. if (record.isDomain === 1 && record.status === 1) {
  373. dropDown.push(
  374. {
  375. label: 'GTM代码',
  376. onClick: addGtm.bind(null, record),
  377. },
  378. {
  379. label: 'Google Ads',
  380. onClick: bindGoogleAds.bind(null, record),
  381. }
  382. );
  383. }
  384. // 当前是管理员,并且站点是被删除状态
  385. if (isAdmin.value && record.status === 0) {
  386. dropDown.push({
  387. label: '资源删除',
  388. popConfirm: {
  389. title: '该站点将从系统中删除,站点资源将会保留15天,是否确认删除',
  390. confirm: handleDelete.bind(null, record),
  391. placement: 'topLeft',
  392. },
  393. });
  394. }
  395. return dropDown;
  396. }
  397. // 添加gtm
  398. function addGtm(r) {
  399. gtmRef.value.init(r);
  400. }
  401. // 询盘设置
  402. function setEnquiry(record) {
  403. siteSetEnquiryRef.value.init(record);
  404. }
  405. function setSohoeb2bOrder(record) {
  406. sohoeb2bOrderRef.value.init(record);
  407. }
  408. function wpSiteRelease(record) {
  409. siteReleaseRef.value.init(record);
  410. }
  411. /**
  412. * 查询
  413. */
  414. function searchQuery() {
  415. reload();
  416. }
  417. /**
  418. * 重置
  419. */
  420. function searchReset() {
  421. formRef.value.resetFields();
  422. if (queryParam.status) {
  423. delete queryParam.status;
  424. }
  425. if (queryParam.channelProviderId) {
  426. delete queryParam.channelProviderId;
  427. }
  428. selectedRowKeys.value = [];
  429. //刷新数据
  430. reload();
  431. }
  432. function handleProcess(record, type) {
  433. seoProcessVisible.value = true;
  434. processTitle.value = record.name;
  435. seoProcessRef.value.init(record, type);
  436. seoProcessRef.value.isCustomer = true;
  437. }
  438. function closeProcess() {
  439. seoProcessVisible.value = false;
  440. }
  441. function bindGoogleAds(record) {
  442. googleAdsModalRef.value.init({ record });
  443. }
  444. </script>
  445. <style lang="less" scoped>
  446. .jeecg-basic-table-form-container {
  447. padding: 0;
  448. .table-page-search-submitButtons {
  449. display: block;
  450. margin-bottom: 24px;
  451. white-space: nowrap;
  452. }
  453. .query-group-cust {
  454. min-width: 100px !important;
  455. }
  456. .query-group-split-cust {
  457. width: 30px;
  458. display: inline-block;
  459. text-align: center;
  460. }
  461. .ant-form-item:not(.ant-form-item-with-help) {
  462. margin-bottom: 16px;
  463. height: 32px;
  464. }
  465. :deep(.ant-picker),
  466. :deep(.ant-input-number) {
  467. width: 100%;
  468. }
  469. }
  470. </style>