LeftContent.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import { css, cx } from "@linaria/core";
  2. import {
  3. IconCamera,
  4. IconCube,
  5. IconDashboard,
  6. IconDownload,
  7. IconSettings,
  8. } from "@queenjs/icons";
  9. import { Avatar, Divider } from "ant-design-vue";
  10. import { defineUI, queenApi } from "queenjs";
  11. import { defineComponent } from "vue";
  12. import { array, object } from "vue-types";
  13. import Logo from "./Logo";
  14. import { UserController } from "./UserController";
  15. import dayjs from "dayjs";
  16. import Payment from "../../Payment";
  17. import { useAuth } from "@queenjs-modules/auth";
  18. export default defineUI({
  19. props: {
  20. Controller: object<UserController>().isRequired,
  21. },
  22. setup(props) {
  23. const auth = useAuth();
  24. const footerOptions: TextListProps[] = [
  25. {
  26. label: "退出",
  27. icon: IconDownload,
  28. onClick: () => props.Controller.loginOut(),
  29. },
  30. ];
  31. const menuOptions = [
  32. {
  33. link: "/workbench/promotion",
  34. label: "我的作品",
  35. icon: IconDashboard,
  36. // suffix: "7",
  37. },
  38. {
  39. link: "/workbench/collection",
  40. label: "作品集",
  41. icon: IconCube,
  42. // suffix: "32",
  43. },
  44. {
  45. link: "/workbench/category",
  46. label: "我的分类",
  47. icon: IconCube,
  48. // suffix: "32",
  49. },
  50. {
  51. link: "/workstage/material",
  52. label: "我的素材",
  53. icon: IconCamera,
  54. // suffix: "32",
  55. },
  56. {
  57. link: "/settings",
  58. label: "个人资料",
  59. icon: IconSettings,
  60. },
  61. ];
  62. function showPayment() {
  63. queenApi.dialog(<Payment />, { width: "12rem" }, [auth]);
  64. }
  65. return () => {
  66. const { userInfo } = props.Controller.state;
  67. const isSys = (userInfo.roles || []).indexOf("system") > -1;
  68. return (
  69. <div class={cx(rootStyles, "px-25px py-16px h-1/1 flex flex-col")}>
  70. <div>
  71. <Logo />
  72. </div>
  73. <div class="my-50px flex items-center">
  74. <Avatar size={76} src={userInfo.avatar} />
  75. <div class="ml-20px flex-1">
  76. <p class="mb-10px text-16px font-bold">{userInfo.name} {isSys?"(平台账号)":""}</p>
  77. <div
  78. class="text-12px text-gray cursor-pointer"
  79. style={{ color: "#E88B00" }}
  80. onClick={showPayment}
  81. >
  82. {userInfo.saas
  83. ? "VIP 到期时间:" +
  84. dayjs(userInfo.saas.Exp).format("YYYY.MM.DD")
  85. : "免费版(限3个推广)"}
  86. </div>
  87. </div>
  88. </div>
  89. {/* <router-link to="/">
  90. <TextListItem
  91. option={{
  92. label: "资源中心",
  93. suffix: <span class="icon_new">new</span>,
  94. icon: (
  95. <img
  96. class="w-18px mr-10px"
  97. src={require("@/assets/imgs/img-resource.png")}
  98. alt=""
  99. />
  100. ),
  101. }}
  102. />
  103. </router-link> */}
  104. <Divider class="!-mt-10px" />
  105. <div class="flex-1">
  106. {menuOptions?.map((option, index) => (
  107. <router-link to={option.link} key={index}>
  108. <TextListItem key={index} option={option} />
  109. </router-link>
  110. ))}
  111. </div>
  112. <div class="mb-30px">
  113. <TextList options={footerOptions} />
  114. </div>
  115. </div>
  116. );
  117. };
  118. },
  119. });
  120. const rootStyles = css`
  121. .icon_new {
  122. border-radius: 14px;
  123. padding: 5px 10px;
  124. text-transform: uppercase;
  125. font-size: 12px;
  126. line-height: 1;
  127. background: linear-gradient(90deg, #9788ff 0%, #7e6bff 100%);
  128. color: #fff;
  129. }
  130. .router-link-exact-active {
  131. display: block;
  132. border-radius: 4px;
  133. background-color: #414141;
  134. > div {
  135. color: @inf-text-color;
  136. }
  137. }
  138. `;
  139. type TextListProps = {
  140. label?: string;
  141. suffix?: any;
  142. icon?: any;
  143. link?: string;
  144. onClick?: () => void;
  145. };
  146. const TextList = defineComponent({
  147. props: {
  148. options: array<TextListProps>(),
  149. },
  150. setup(props) {
  151. return () => {
  152. return (
  153. <div>
  154. {props.options?.map((option, index) => (
  155. <TextListItem key={index} option={option} />
  156. ))}
  157. </div>
  158. );
  159. };
  160. },
  161. });
  162. const TextListItem = defineComponent({
  163. props: { option: object<TextListProps>() },
  164. setup(props) {
  165. return () => {
  166. const { option = {} } = props;
  167. return (
  168. <div
  169. class={cx("flex items-center justify-between", itemStyles)}
  170. onClick={() => option.onClick?.()}
  171. >
  172. {option.icon && <option.icon class="mr-8px text-20px" />}
  173. <div class="flex-1">{option.label}</div>
  174. {option.suffix && typeof option.suffix == "string" ? (
  175. <span>{option.suffix}</span>
  176. ) : (
  177. option.suffix
  178. )}
  179. </div>
  180. );
  181. };
  182. },
  183. });
  184. const itemStyles = css`
  185. margin-top: 10px;
  186. border-radius: 4px;
  187. padding: 10px 25px 10px 20px;
  188. color: @inf-text-sub-color;
  189. cursor: pointer;
  190. &:hover {
  191. background: #414141;
  192. }
  193. `;