TopContent.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <template>
  2. <div class="head-content">
  3. <div class="head-content-logo">
  4. <img :src="Logo" />
  5. </div>
  6. <div class="head-content-wrap">
  7. <span class="head-content-wrap__label">市场迷雾?罗经开路!</span>
  8. <span class="head-content-wrap__title">
  9. Lookeen 是一个服务于首次出海客户的 AI 商情系统(GTM Analytics
  10. Tools 市场进入分析工具)。目的是提供客户自己的产品品类在目标市场的商业情报,降低用户对产品在目标市场的不确定性。
  11. </span>
  12. <div class="head-content-wrap__step">
  13. <span class="label">只需三步</span>
  14. <span class="tip">(每月可免费获取3次商品分析)</span>
  15. </div>
  16. <div class="head-content-wrap__info">
  17. <CountrySelct ref="CountrySelctRef" v-show="currentStep === 1"></CountrySelct>
  18. <ProductDescription
  19. ref="ProductDescriptionRef"
  20. v-show="currentStep === 2"
  21. ></ProductDescription>
  22. <CompetitorWebsite
  23. ref="CompetitorWebsiteRef"
  24. v-show="currentStep === 3"
  25. ></CompetitorWebsite>
  26. <el-button v-if="currentStep !== 1" @click="prevStep">上一步</el-button>
  27. <el-button v-if="currentStep !== 3" @click="nextStep">下一步</el-button>
  28. <el-button v-if="currentStep === 3" :loading="btnLoading" @click="acceptRecod"
  29. >获取报告</el-button
  30. >
  31. </div>
  32. </div>
  33. <LoginDialog :visible="visible" @update:visible="(val) => (visible = val)" :callback="dialogConfirmCallback"></LoginDialog>
  34. </div>
  35. </template>
  36. <script lang="ts" setup>
  37. import { ref, computed, reactive } from 'vue';
  38. import { useMainStore } from '../store';
  39. import { useRouter } from 'vue-router';
  40. import CountrySelct from '@/components/CountrySelct.vue';
  41. import ProductDescription from '@/components/ProductDescription.vue';
  42. import CompetitorWebsite from '@/components/CompetitorWebsite.vue';
  43. import LoginDialog from '@/components/LoginDialog.vue';
  44. import Logo from '@/assets/images/logo.png';
  45. import { showMessage } from '@/utils/common';
  46. const mainStore = useMainStore();
  47. const router = useRouter();
  48. const currentStep = computed(() => mainStore.getCurrentStep);
  49. const CountrySelctRef = ref();
  50. const ProductDescriptionRef = ref();
  51. const CompetitorWebsiteRef = ref();
  52. const visible = ref<boolean>(false);
  53. const btnLoading = ref<boolean>(false);
  54. const validate = () => {
  55. const { locationName, productName, description } = getFormData();
  56. let message: string = '';
  57. switch (currentStep.value) {
  58. case 1:
  59. if (!productName) {
  60. message = '请输入产品名称';
  61. break;
  62. }
  63. // if (!locationName) {
  64. // message = '请选择目标区域市场';
  65. // break;
  66. // }
  67. break;
  68. // case 2:
  69. // if (!description) {
  70. // message = '请输入产品描述';
  71. // break;
  72. // }
  73. // break;
  74. default:
  75. break;
  76. }
  77. return message;
  78. };
  79. const nextStep = () => {
  80. const message = validate();
  81. if (message) {
  82. return showMessage({
  83. type: 'error',
  84. message
  85. });
  86. }
  87. mainStore.setCurrentStep(currentStep.value + 1);
  88. };
  89. const prevStep = () => {
  90. mainStore.setCurrentStep(currentStep.value - 1);
  91. };
  92. const getFormData = () => {
  93. const locationName = CountrySelctRef.value.getLocationName();
  94. const productName = CountrySelctRef.value.getProductName();
  95. const description = ProductDescriptionRef.value.getDescription();
  96. const competitorWebsite = CompetitorWebsiteRef.value.getWebsite();
  97. return {
  98. locationName,
  99. productName,
  100. description,
  101. competitorWebsite
  102. };
  103. };
  104. const isValidUrl = (url: string) => {
  105. const pattern = /^(https?:\/\/|ftp:\/\/)([a-zA-Z0-9.-]+)(:[0-9]+)?(\/[^\s]*)?$/;
  106. return pattern.test(url);
  107. };
  108. const validateCompetitorWebsite = (site: string) => {
  109. if (!site.trim()) return true;
  110. const list = site.split(',');
  111. return list.every((item) => isValidUrl(item));
  112. };
  113. const dialogConfirmCallback = () => {
  114. const formData = getFormData();
  115. btnLoading.value = false;
  116. mainStore.setFormData(formData);
  117. };
  118. const acceptRecod = async () => {
  119. const formData = getFormData();
  120. const { competitorWebsite } = formData;
  121. const result = validateCompetitorWebsite(competitorWebsite);
  122. if (!result) {
  123. showMessage({
  124. type: 'error',
  125. message: '请输入正确的竞品网站'
  126. });
  127. btnLoading.value = false;
  128. return;
  129. }
  130. visible.value = true;
  131. return;
  132. // router.push('/record');
  133. };
  134. </script>
  135. <style lang="scss" scoped>
  136. .head-content {
  137. width: 100%;
  138. height: 100%;
  139. position: relative;
  140. &-logo {
  141. position: absolute;
  142. width: 320px;
  143. height: 88px;
  144. left: 260px;
  145. top: 32px;
  146. img {
  147. width: 100%;
  148. height: 100%;
  149. object-fit: cover;
  150. }
  151. }
  152. &-wrap {
  153. position: absolute;
  154. display: flex;
  155. flex-direction: column;
  156. width: 663px;
  157. height: 548px;
  158. left: 280px;
  159. top: 125px;
  160. &__label {
  161. font-weight: bold;
  162. font-size: 40px;
  163. color: #282e30;
  164. margin-top: 60px;
  165. }
  166. &__title {
  167. display: inline-block;
  168. width: 100%;
  169. height: 66px;
  170. font-weight: 400;
  171. font-size: 16px;
  172. color: #282e30;
  173. line-height: 22px;
  174. overflow: hidden;
  175. text-overflow: ellipsis;
  176. margin-top: 20px;
  177. }
  178. &__step {
  179. margin-top: 60px;
  180. .label {
  181. font-weight: bold;
  182. font-size: 24px;
  183. color: var(--promotion--color-primary);
  184. }
  185. .tip {
  186. font-weight: 400;
  187. font-size: 12px;
  188. color: #282e30;
  189. margin-left: 10px;
  190. }
  191. }
  192. &__info {
  193. display: flex;
  194. align-items: center;
  195. height: 68px;
  196. margin-top: 10px;
  197. :deep(.el-button) {
  198. width: 110px;
  199. height: 48px;
  200. background-color: var(--promotion--color-primary);
  201. font-weight: 400;
  202. font-size: 16px;
  203. color: #ffffff;
  204. border-radius: 0;
  205. margin-left: 10px;
  206. }
  207. }
  208. }
  209. }
  210. </style>