liveDrawer.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <template>
  2. <BasicDrawer
  3. v-bind="$attrs"
  4. @register="registerDrawer"
  5. showFooter
  6. :title="getTitle"
  7. width="60%"
  8. @ok="handleSubmit"
  9. @close="handleClose"
  10. >
  11. <div class="entry-x">
  12. <BasicForm @register="registerForm">
  13. <template #map>
  14. <!-- <Card style="width: 300px; height: 300px"> -->
  15. <div ref="wrapRef" style="width: 100%; height: 400px"></div>
  16. <!-- </Card> -->
  17. </template>
  18. <!-- ="{ model, field }" -->
  19. <template #detailAddr>
  20. <a-input
  21. class="live-drawer"
  22. v-bind="$attrs"
  23. v-model:value="detailAddr"
  24. :allowClear="true"
  25. placeholder=""
  26. >
  27. <template #addonAfter>
  28. <a-button type="primary" class="mr-10px" @click="handleMapSearch">
  29. {{ t('common.queryText') }}
  30. </a-button>
  31. <a-button @click="handleMapReset"> {{ t('common.resetText') }}</a-button>
  32. </template>
  33. </a-input>
  34. </template>
  35. </BasicForm>
  36. </div>
  37. </BasicDrawer>
  38. </template>
  39. <script lang="ts">
  40. import { defineComponent, ref, computed, unref, nextTick, reactive } from 'vue';
  41. import { BasicForm, useForm, FormSchema } from '/@/components/Form/index';
  42. // import { Card } from 'ant-design-vue';
  43. import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  44. // import { useMessage } from '/@/hooks/web/useMessage';
  45. import { useI18n } from '/@/hooks/web/useI18n';
  46. import {
  47. brandTypeListApi,
  48. uploadLiveApi,
  49. getAllSceneApi,
  50. uploadLiveVideoApi,
  51. // LiveSceneDeleteApi,
  52. } from '/@/api/scene/live';
  53. import { data as CascaderData } from '/@/utils/cascaderData';
  54. import { useScript } from '/@/hooks/web/useScript';
  55. const A_MAP_URL = 'https://webapi.amap.com/maps?v=2.0&key=e661b00bdf2c44cccf71ef6070ef41b8';
  56. // const A_MAP_URL = 'https://webapi.amap.com/maps?v=2.0&key=5a2d384532ae531bf99bd8487c4f03d2';
  57. // const A_MAP_URL = 'https://webapi.amap.com/maps?v=1.4.10&key=e661b00bdf2c44cccf71ef6070ef41b8';
  58. //webapi.amap.com/maps?v=1.4.10&key=e661b00bdf2c44cccf71ef6070ef41b8
  59. // Card
  60. export default defineComponent({
  61. name: 'MenuDrawer',
  62. components: { BasicDrawer, BasicForm },
  63. emits: ['success', 'register'],
  64. setup() {
  65. const isUpdate = ref(true);
  66. const detailAddr = ref('');
  67. const wrapRef = ref<HTMLDivElement | null>(null);
  68. interface AddressComponentType {
  69. city: string;
  70. district: string;
  71. province: string;
  72. }
  73. interface GeocodesType {
  74. adcode: string;
  75. addressComponent: AddressComponentType;
  76. formattedAddress: string;
  77. location: {
  78. lng: string;
  79. lat: string;
  80. };
  81. }
  82. let map;
  83. // Lat(120.262337, 30.178285),
  84. const defaultAddress = reactive({
  85. address: '山阴路688号恒隆广场B座1217',
  86. // address: '权晖花园21栋',
  87. lng: 120.262337,
  88. lat: 30.178285,
  89. location: ['33', '3301', '330109'],
  90. province: '浙江省',
  91. city: '杭州市',
  92. district: '萧山区',
  93. });
  94. console.log('defaultAddress', defaultAddress);
  95. const { toPromise } = useScript({ src: A_MAP_URL });
  96. const { t } = useI18n();
  97. // const { createMessage } = useMessage();
  98. const schemas: FormSchema[] = [
  99. {
  100. field: 'type',
  101. label: t('routes.scenes.liveType'),
  102. component: 'ApiSelect',
  103. // colProps: {
  104. // xl: 5,
  105. // xxl: 5,
  106. // },
  107. required: true,
  108. componentProps: {
  109. api: brandTypeListApi,
  110. resultField: 'list',
  111. labelField: 'name',
  112. valueField: 'id',
  113. params: {
  114. page: 1,
  115. limit: 1000,
  116. },
  117. },
  118. },
  119. {
  120. field: 'name',
  121. component: 'Input',
  122. label: t('routes.scenes.liveName'),
  123. required: true,
  124. },
  125. {
  126. field: 'appListPicUrl',
  127. label: t('routes.scenes.appListPicUrl'),
  128. component: 'Upload',
  129. helpMessage: '推荐大小:400 * 400 像素',
  130. required: true,
  131. colProps: {
  132. span: 10,
  133. },
  134. componentProps: {
  135. api: uploadLiveApi,
  136. maxgoodsNumber: 1,
  137. afterFetch: function (data) {
  138. Reflect.set(data, 'url', data.message.url);
  139. return data;
  140. },
  141. },
  142. },
  143. {
  144. field: 'sceneUrl',
  145. label: t('routes.scenes.sceneUrl'),
  146. component: 'ApiSelect',
  147. required: true,
  148. colProps: {
  149. span: 10,
  150. },
  151. componentProps: {
  152. api: getAllSceneApi,
  153. },
  154. },
  155. {
  156. field: 'location',
  157. label: '直播间位置',
  158. component: 'ApiCascader',
  159. componentProps: {
  160. api: () => {
  161. return CascaderData;
  162. },
  163. apiParamKey: 'provinceCode',
  164. dataField: 'children',
  165. labelField: 'name',
  166. valueField: 'code',
  167. // numberToString: true,
  168. isLeaf: (record) => {
  169. return !(record.levelType < 3);
  170. },
  171. onChange: (data) => {
  172. console.log('data', data);
  173. defaultAddress.location = data;
  174. },
  175. },
  176. colProps: {
  177. span: 20,
  178. },
  179. },
  180. {
  181. field: 'detailAddr',
  182. label: t('routes.scenes.detailAddr'),
  183. component: 'Input',
  184. slot: 'detailAddr',
  185. colProps: {
  186. span: 10,
  187. },
  188. },
  189. {
  190. field: 'map',
  191. label: '地图位置',
  192. component: 'Input',
  193. slot: 'map',
  194. colProps: {
  195. span: 20,
  196. },
  197. },
  198. {
  199. field: 'picList',
  200. label: '直播间图片',
  201. component: 'Upload',
  202. componentProps: {
  203. api: uploadLiveApi,
  204. maxSize: 5,
  205. emptyHidePreview: true,
  206. maxNumber: 15,
  207. accept: ['image/*'],
  208. afterFetch: function (data) {
  209. Reflect.set(data, 'url', data.message.url);
  210. return data;
  211. },
  212. },
  213. colProps: {
  214. span: 20,
  215. },
  216. },
  217. {
  218. field: 'introduceVideo',
  219. label: '视频',
  220. component: 'Upload',
  221. componentProps: {
  222. api: uploadLiveVideoApi,
  223. maxSize: 5,
  224. emptyHidePreview: true,
  225. maxNumber: 15,
  226. accept: ['video/*'],
  227. afterFetch: function (data) {
  228. Reflect.set(data, 'url', data.message.video);
  229. return data;
  230. },
  231. },
  232. colProps: {
  233. span: 20,
  234. },
  235. },
  236. {
  237. field: 'contractPhone',
  238. component: 'Input',
  239. label: t('routes.scenes.contractPhone'),
  240. required: true,
  241. helpMessage: ['支持填写400(400-xxx-xxxx)热线、手机号等联系方式'],
  242. },
  243. ];
  244. // updateSchema, validate
  245. const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
  246. labelWidth: 120,
  247. schemas: schemas,
  248. showActionButtonGroup: false,
  249. baseColProps: { lg: 24, md: 24 },
  250. });
  251. const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  252. resetFields();
  253. setDrawerProps({ confirmLoading: false });
  254. isUpdate.value = !!data?.isUpdate;
  255. if (unref(isUpdate)) {
  256. console.log('data.record', data);
  257. }
  258. initMap();
  259. });
  260. async function initMap() {
  261. await toPromise();
  262. await nextTick();
  263. const wrapEl = unref(wrapRef);
  264. console.log('wrapEl', wrapEl);
  265. if (!wrapEl) return;
  266. // center: [this.longitude || 120.262337, this.latitude || 30.178285],
  267. // const geocoder = new AMap.Geocoder({});
  268. const AMap = (window as any).AMap;
  269. map = new AMap.Map(wrapEl, {
  270. zoom: 18,
  271. center: [120.262337, 30.178285],
  272. viewMode: '3D',
  273. resizeEnable: true,
  274. floorControl: true,
  275. showIndoorMap: true,
  276. });
  277. AMap.plugin('AMap.Geocoder', function () {
  278. var geocoder = new AMap.Geocoder({
  279. // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
  280. // city: '010',
  281. });
  282. geocoder.getLocation(defaultAddress.address, async function (status, result) {
  283. if (status === 'complete' && result.info === 'OK') {
  284. // result中对应详细地理坐标信息
  285. console.log('result', result);
  286. const { geocodes } = result;
  287. if (geocodes?.length > 0) {
  288. const { adcode, addressComponent } = geocodes[0] as any as GeocodesType;
  289. defaultAddress.location = getCodeArray(adcode);
  290. await updateSchema({
  291. field: 'location',
  292. componentProps: {
  293. displayRenderArray: [
  294. addressComponent.province,
  295. addressComponent.city,
  296. addressComponent.district,
  297. ],
  298. },
  299. });
  300. await setFieldsValue({
  301. location: defaultAddress.location,
  302. // detailAddr: defaultAddress.address,
  303. });
  304. detailAddr.value = defaultAddress.address;
  305. }
  306. }
  307. });
  308. // const marker = new AMap.Marker({
  309. // position: new AMap.LngLat(defaultAddress.lng, defaultAddress.lat),
  310. // title: 'lala',
  311. // });
  312. // map && map.add(marker);
  313. });
  314. }
  315. function getCodeArray(code: string) {
  316. const pdCode = code.slice(0, 2);
  317. const cityCode = code.slice(2, 4);
  318. return [pdCode, cityCode, code];
  319. }
  320. const getTitle = computed(() => (!unref(isUpdate) ? '新增直播间' : '编辑直播间'));
  321. async function handleMapSearch() {
  322. if (detailAddr.value?.length > 0) {
  323. console.log('detailAddr.value', detailAddr.value);
  324. const AMap = (window as any).AMap;
  325. console.log('adcode', defaultAddress.location[2]);
  326. AMap.plugin('AMap.Geocoder', function () {
  327. const geocoder = new AMap.Geocoder({
  328. // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
  329. city:
  330. defaultAddress.location[2] ||
  331. defaultAddress.location[1] ||
  332. defaultAddress.location[0],
  333. // adcode: defaultAddress.location[2],
  334. // citycode: '0571',
  335. });
  336. console.log('geocoder', geocoder);
  337. geocoder.getLocation(detailAddr.value, async function (status, result) {
  338. if (status === 'complete' && result.info === 'OK') {
  339. // result中对应详细地理坐标信息
  340. console.log('result', result);
  341. const { geocodes } = result;
  342. if (geocodes?.length > 0) {
  343. // map.setCenter([lng, lat]);
  344. const { adcode, addressComponent, formattedAddress, location } =
  345. geocodes[0] as any as GeocodesType;
  346. console.log('location', location);
  347. map.setCenter(location);
  348. const marker = new AMap.Marker({
  349. position: new AMap.LngLat(location.lng, location.lat),
  350. title: formattedAddress,
  351. });
  352. map.add(marker);
  353. defaultAddress.location = getCodeArray(adcode);
  354. await updateSchema({
  355. field: 'location',
  356. componentProps: {
  357. displayRenderArray: [
  358. addressComponent.province,
  359. addressComponent.city,
  360. addressComponent.district,
  361. ],
  362. },
  363. });
  364. await setFieldsValue({
  365. location: defaultAddress.location,
  366. // detailAddr: defaultAddress.address,
  367. });
  368. // detailAddr.value = defaultAddress.address;
  369. }
  370. }
  371. });
  372. });
  373. }
  374. }
  375. async function handleMapReset() {
  376. defaultAddress.location = ['33', '3301', '330109'];
  377. detailAddr.value = '山阴路688号恒隆广场B座1217';
  378. handleMapSearch();
  379. }
  380. async function handleSubmit() {
  381. try {
  382. map && map.destroy();
  383. const values = await validate();
  384. console.log('values', values);
  385. resetFields();
  386. closeDrawer();
  387. } catch (error) {}
  388. }
  389. async function handleClose() {
  390. map && map.destroy();
  391. resetFields();
  392. closeDrawer();
  393. }
  394. return {
  395. detailAddr,
  396. registerDrawer,
  397. registerForm,
  398. getTitle,
  399. handleSubmit,
  400. wrapRef,
  401. handleMapSearch,
  402. handleMapReset,
  403. handleClose,
  404. t,
  405. };
  406. },
  407. });
  408. </script>
  409. <style lang="less">
  410. .live-drawer {
  411. .ant-input-group-addon {
  412. padding-right: 0;
  413. background-color: transparent;
  414. border: none;
  415. button {
  416. font-size: 14px;
  417. }
  418. }
  419. }
  420. </style>