CollectionModal.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import { css } from "@linaria/core";
  2. import { Button, Input, Select } from "ant-design-vue";
  3. import { SearchOutlined } from "@ant-design/icons-vue";
  4. import { defineComponent, reactive } from "vue";
  5. import { any } from "vue-types";
  6. import { Image } from "@queenjs/ui";
  7. import { useResource } from "@/modules/resource";
  8. import dayjs from "dayjs";
  9. import { queenApi, useModal } from "queenjs";
  10. import { useEditor } from "@/modules/editor";
  11. export default defineComponent({
  12. props: {
  13. record: any().isRequired,
  14. },
  15. setup(props, { slots }) {
  16. const resource = useResource();
  17. const state = reactive({
  18. currCollection: {} as any,
  19. searchVal: "",
  20. });
  21. const editor = useEditor();
  22. const modal = useModal();
  23. const EmptyHistory = () => {
  24. return (
  25. <div
  26. class={
  27. "inline-flex flex-col items-center justify-center w-full h-full rounded-6px"
  28. }
  29. style={{ background: "#F1F2F4" }}
  30. >
  31. <div>
  32. <img
  33. width={86}
  34. height={66}
  35. src={require("@/assets/imgs/empty_history.png")}
  36. />
  37. </div>
  38. <div class={"text-12px mt-16px text-gray"}>暂无历史发送信息</div>
  39. </div>
  40. );
  41. };
  42. const EmptyCollection = () => {
  43. return (
  44. <div class={"text-center"}>
  45. <div
  46. class={
  47. "w-full h-290px inline-flex flex-col items-center justify-center rounded-6px"
  48. }
  49. style={{ background: "#F1F2F4" }}
  50. >
  51. <img
  52. class={"object-contain"}
  53. width={200}
  54. height={142}
  55. src={require("@/assets/imgs/404.png")}
  56. />
  57. </div>
  58. <div class={"text-12px mt-18px text-gray"}>
  59. 请输入正确的接收地址以获取信息
  60. </div>
  61. </div>
  62. );
  63. };
  64. const workPreview = async (currId: string) => {
  65. await editor.actions.initDesign(currId, false);
  66. previewInModal("当前提交");
  67. };
  68. const historyPreview = async (hisId: string) => {
  69. await editor.actions.initWkDesign(hisId);
  70. previewInModal("历史提交");
  71. };
  72. const collectionPreview = async (collection: any) => {
  73. if (collection.introLink) {
  74. window.open(collection.introLink);
  75. return;
  76. }
  77. if (collection.introH5Id) {
  78. await editor.actions.initDesign(collection.introH5Id, false);
  79. previewInModal("详情介绍");
  80. }
  81. };
  82. const previewInModal = (title: string) => {
  83. editor.actions.switchMode("preview");
  84. resource.showModal(
  85. <div class={"!p-0"}>
  86. <div class={"h-600px scrollbar"}>
  87. <editor.components.Preview class="pointer-events-none" />
  88. </div>
  89. </div>,
  90. {
  91. title: title,
  92. destroyOnClose: true,
  93. }
  94. );
  95. };
  96. const itemRender = (data: any) => {
  97. return (
  98. <div class={"flex h-full overflow-hidden"}>
  99. <div class={[itemPreview, "relative"]}>
  100. <Image class="w-160px h-160px rounded-6px" src={data?.thumbnail} />
  101. <div
  102. class={"icon_preview absolute top-8px right-8px"}
  103. onClick={() => workPreview(data._id)}
  104. >
  105. <img
  106. class={"w-20px h-20px"}
  107. src={require("@/assets/imgs/icon_preview.png")}
  108. />
  109. </div>
  110. </div>
  111. <div class={"flex-1 pl-20px flex flex-col"}>
  112. <div class={"text-18px"}>{data.title}</div>
  113. <div class={"my-12px text-gray break-all flex-1 overflow-hidden"}>
  114. {data.desc}
  115. </div>
  116. </div>
  117. </div>
  118. );
  119. };
  120. const itemHistory = () => {
  121. if (!state.currCollection.h5) {
  122. return null;
  123. }
  124. const h5 = state.currCollection.h5[0];
  125. const wks = state.currCollection.wks;
  126. return (
  127. <div class={"flex h-full overflow-hidden"}>
  128. <div class={[itemPreview, "relative"]}>
  129. <Image class="w-160px h-160px rounded-6px" src={h5.thumbnail} />
  130. <div
  131. class={"icon_preview absolute top-8px right-8px"}
  132. onClick={() => historyPreview(wks.id)}
  133. >
  134. <img
  135. class={"w-20px h-20px"}
  136. src={require("@/assets/imgs/icon_preview.png")}
  137. />
  138. </div>
  139. </div>
  140. <div class={"flex-1 pl-20px flex flex-col"}>
  141. <div class={"text-18px"}>{h5.title}</div>
  142. <div class={"my-12px text-gray break-all flex-1 overflow-hidden"}>
  143. {h5.desc}
  144. </div>
  145. <div class={"text-12px text-gray"}>
  146. 提交日期:{dayjs(wks.endTime).format("YYYY-MM-DD")}
  147. </div>
  148. </div>
  149. </div>
  150. );
  151. };
  152. const CollectionRender = () => {
  153. const data = state.currCollection;
  154. return (
  155. <div>
  156. <div class={"text-18px mb-20px"}>{data.title}</div>
  157. <div class={[itemPreview, "w-full h-290px rounded-6px relative"]}>
  158. <Image class={"w-full h-full rounded-6px"} src={data.cover} />
  159. {(data.introLink || data.introH5Id) && (
  160. <div
  161. class={"icon_preview absolute top-10px right-10px"}
  162. onClick={() => {
  163. collectionPreview(data);
  164. }}
  165. >
  166. <img
  167. class={"w-30px h-30px"}
  168. src={require("@/assets/imgs/icon_preview.png")}
  169. />
  170. </div>
  171. )}
  172. </div>
  173. <div class={"flex justify-between items-center mt-15px"}>
  174. <div>
  175. {data.logo && (
  176. <Image
  177. class={"w-42px h-42px object-cover rounded-2px"}
  178. src={data.logo}
  179. />
  180. )}
  181. {data.endTime && (
  182. <span class={"pl-20px text-gray"}>
  183. 截止日期:{dayjs(data.endTime).format("YYYY-MM-DD")}
  184. </span>
  185. )}
  186. </div>
  187. {data.status && (
  188. <div
  189. class={
  190. "text-16px text-white bg-blue-500 px-20px py-10px rounded-4px"
  191. }
  192. >
  193. {data.status}
  194. </div>
  195. )}
  196. </div>
  197. </div>
  198. );
  199. };
  200. const search = async () => {
  201. if (!state.searchVal) {
  202. return false;
  203. }
  204. const collection = await resource.actions.searchCollection(
  205. state.searchVal,
  206. props.record._id
  207. );
  208. if (!collection) {
  209. return;
  210. }
  211. state.currCollection = collection[0];
  212. };
  213. const commit = async () => {
  214. const res = await resource.actions.commitCollection({
  215. id: state.currCollection._id,
  216. h5Id: props.record._id,
  217. });
  218. if (!res) {
  219. return;
  220. }
  221. modal.submit();
  222. queenApi.messageSuccess("发送成功");
  223. };
  224. return () => {
  225. return (
  226. <div class={ModalStyle}>
  227. <div class={"space-y-14px"}>
  228. <div
  229. class={"flex items-center bg-white px-30px py-18px rounded-6px"}
  230. >
  231. <div class={"text-16px"}>接收地址</div>
  232. <div class={"flex-1 px-30px"}>
  233. <Input
  234. class={"w-full text-center"}
  235. placeholder={"请输入接收地址"}
  236. value={state.searchVal}
  237. onChange={(e) => {
  238. state.searchVal = e.target.value || "";
  239. }}
  240. ></Input>
  241. </div>
  242. <div>
  243. <Button
  244. type="primary"
  245. ghost
  246. icon={<SearchOutlined />}
  247. onClick={search}
  248. >
  249. 查询
  250. </Button>
  251. </div>
  252. </div>
  253. <div class={"bg-white px-30px py-20px"}>
  254. {state.currCollection._id
  255. ? CollectionRender()
  256. : EmptyCollection()}
  257. </div>
  258. <div class={"flex items-center space-x-16px"}>
  259. <div class={"flex-1 bg-white px-30px py-18px rounded-6px"}>
  260. <div class={"text-16px"}>当前发送</div>
  261. <div class={"mt-20px h-160px"}>{itemRender(props.record)}</div>
  262. </div>
  263. <div class={"flex-1 bg-white px-30px py-18px rounded-6px"}>
  264. <div class={"text-16px"}>历史发送</div>
  265. <div class={"mt-20px h-160px"}>
  266. {state.currCollection.h5 ? itemHistory() : EmptyHistory()}
  267. </div>
  268. </div>
  269. </div>
  270. </div>
  271. <div class={"text-center mt-24px"}>
  272. <Button
  273. type="primary"
  274. ghost
  275. size={"large"}
  276. class={"w-240px"}
  277. disabled={state.currCollection._id ? false : true}
  278. onClick={commit}
  279. >
  280. 确认发送
  281. </Button>
  282. </div>
  283. </div>
  284. );
  285. };
  286. },
  287. });
  288. const itemPreview = css`
  289. &:hover {
  290. .icon_preview {
  291. opacity: 1;
  292. }
  293. }
  294. .icon_preview {
  295. opacity: 0;
  296. cursor: pointer;
  297. }
  298. `;
  299. const ModalStyle = css`
  300. color: #111;
  301. .ant-input {
  302. border-radius: 4px;
  303. border-color: rgba(51, 51, 51, 0.3);
  304. color: #111;
  305. &::placeholder {
  306. color: #999;
  307. }
  308. }
  309. .ant-select:not(.ant-select-customize-input) {
  310. .ant-select-selector {
  311. border-radius: 4px;
  312. border-color: rgba(51, 51, 51, 0.3);
  313. color: #111;
  314. .ant-select-selection-search {
  315. input {
  316. text-align: center;
  317. }
  318. }
  319. }
  320. }
  321. .ant-select-selection-placeholder {
  322. color: #999;
  323. }
  324. .ant-btn-background-ghost.ant-btn-primary {
  325. border-radius: 4px;
  326. background-color: rgba(255, 227, 178, 0.3);
  327. }
  328. .ant-btn-background-ghost.ant-btn-primary[disabled] {
  329. color: #fff;
  330. border-color: transparent;
  331. background: #ccc;
  332. text-shadow: none;
  333. box-shadow: none;
  334. &:hover {
  335. color: #fff;
  336. border-color: transparent;
  337. background: #ccc;
  338. text-shadow: none;
  339. box-shadow: none;
  340. }
  341. }
  342. `;