Ver Fonte

:construction: create

visuddhinanda há 1 ano atrás
pai
commit
a1f944f88e

+ 10 - 0
api-v8/app/Http/Api/WatchApi.php

@@ -0,0 +1,10 @@
+<?php
+namespace App\Http\Api;
+
+use App\Models\Notification;
+
+class WatchApi{
+    public static function change($resId,$title,$message){
+        //发送站内信
+    }
+}

+ 32 - 0
api-v8/app/Http/Resources/LikeResource.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Http\Api\UserApi;
+
+class LikeResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $data = [
+            'id' => $this->id,
+            'type' => $this->type,
+            'target_id' => $this->target_id,
+            'target_type' => $this->target_type,
+            'context' => $this->context,
+            'updated_at' => $this->updated_at,
+            'created_at' => $this->created_at
+        ];
+        if($this->user_id){
+            $data['user'] = UserApi::getByUuid($this->user_id);
+        }
+        return $data;
+    }
+}

+ 56 - 0
dashboard-v4/dashboard/src/components/api/like.ts

@@ -0,0 +1,56 @@
+import { IUser } from "../auth/User";
+
+export type TLikeType = "like" | "dislike" | "favorite" | "watch";
+export interface ILikeData {
+  id: string;
+  type: TLikeType;
+  target_id: string;
+  target_type?: string;
+  user: IUser;
+  context?: string | null;
+  selected?: boolean;
+  my_id?: string;
+  count?: number;
+  updated_at?: string;
+  created_at?: string;
+}
+export interface ILikeCount {
+  type: TLikeType;
+  selected?: boolean;
+  my_id?: string;
+  count?: number;
+  user: IUser;
+}
+
+export interface ILikeListResponse {
+  ok: boolean;
+  message: string;
+  data: {
+    rows: ILikeData[];
+    count: number;
+  };
+}
+
+export interface ILikeResponse {
+  ok: boolean;
+  message: string;
+  data: ILikeData;
+}
+
+export interface ILikeCountListResponse {
+  ok: boolean;
+  message: string;
+  data: ILikeCount[];
+}
+export interface ILikeCountResponse {
+  ok: boolean;
+  message: string;
+  data: ILikeCount;
+}
+
+export interface ILikeRequest {
+  type: TLikeType;
+  target_id: string;
+  target_type: string;
+  user_id?: string;
+}

+ 136 - 0
dashboard-v4/dashboard/src/components/like/Like.tsx

@@ -0,0 +1,136 @@
+import { useEffect, useState } from "react";
+import { Button, Space, Tooltip } from "antd";
+import {
+  LikeOutlined,
+  LikeFilled,
+  StarOutlined,
+  StarFilled,
+  EyeOutlined,
+  EyeFilled,
+} from "@ant-design/icons";
+
+import { delete_, get, post } from "../../request";
+import {
+  ILikeCount,
+  ILikeCountListResponse,
+  ILikeCountResponse,
+  ILikeRequest,
+  TLikeType,
+} from "../api/like";
+
+interface IWidget {
+  resId?: string;
+  resType?: string;
+}
+const Like = ({ resId, resType }: IWidget) => {
+  const [like, setLike] = useState<ILikeCount>();
+  const [favorite, setFavorite] = useState<ILikeCount>();
+  const [watch, setWatch] = useState<ILikeCount>();
+
+  useEffect(() => {
+    if (!resId) {
+      return;
+    }
+    const url = `/v2/like?view=count&target_id=${resId}`;
+    console.info("api request", url);
+    get<ILikeCountListResponse>(url).then((json) => {
+      console.info("api response", json);
+      if (json.ok) {
+        setLike(json.data.find((value) => value.type === "like"));
+        setFavorite(json.data.find((value) => value.type === "favorite"));
+        setWatch(json.data.find((value) => value.type === "watch"));
+      }
+    });
+  }, [resId]);
+
+  const setStatus = (data: ILikeCount) => {
+    switch (data.type) {
+      case "like":
+        setLike(data);
+        break;
+      case "favorite":
+        setFavorite(data);
+        break;
+      case "watch":
+        setWatch(data);
+        break;
+    }
+  };
+  const add = (type: TLikeType) => {
+    if (!resId || !resType) {
+      return;
+    }
+    const url = `/v2/like`;
+    post<ILikeRequest, ILikeCountResponse>(url, {
+      type: type,
+      target_id: resId,
+      target_type: resType,
+    }).then((json) => {
+      if (json.ok) {
+        setStatus(json.data);
+      }
+    });
+  };
+
+  const remove = (id?: string) => {
+    if (!resId || !resType || !id) {
+      return;
+    }
+    const url = `/v2/like/${id}`;
+    console.info("api request", url);
+    delete_<ILikeCountResponse>(url).then((json) => {
+      console.info("api response", json);
+      if (json.ok) {
+        setStatus(json.data);
+      }
+    });
+  };
+
+  return (
+    <Space>
+      <Button
+        type="text"
+        icon={like?.selected ? <LikeFilled /> : <LikeOutlined />}
+        onClick={() => {
+          if (like?.selected) {
+            remove(like.my_id);
+          } else {
+            add("like");
+          }
+        }}
+      >
+        {like?.count === 0 ? <></> : like?.count}
+      </Button>
+      <Button
+        type="text"
+        icon={favorite?.selected ? <StarFilled /> : <StarOutlined />}
+        onClick={() => {
+          if (favorite?.selected) {
+            remove(favorite.my_id);
+          } else {
+            add("favorite");
+          }
+        }}
+      >
+        {favorite?.count === 0 ? <></> : favorite?.count}
+      </Button>
+      <Tooltip title="关注">
+        <Button
+          type="text"
+          icon={watch?.selected ? <EyeFilled /> : <EyeOutlined />}
+          onClick={() => {
+            if (watch?.selected) {
+              remove(watch.my_id);
+            } else {
+              add("watch");
+            }
+          }}
+        >
+          {watch?.count === 0 ? <></> : watch?.count}
+        </Button>
+      </Tooltip>
+    </Space>
+  );
+};
+
+export default Like;

+ 64 - 0
dashboard-v4/dashboard/src/components/like/LikeAvatar.tsx

@@ -0,0 +1,64 @@
+import { useEffect, useState } from "react";
+
+import { ILikeData, ILikeListResponse, TLikeType } from "../api/like";
+import { get } from "../../request";
+import User from "../auth/User";
+import { Popover, Space } from "antd";
+import WatchList from "./WatchList";
+import { WatchAddButton } from "./WatchAdd";
+
+interface IWidget {
+  resId?: string;
+  resType?: string;
+  type?: TLikeType;
+}
+const LikeAvatar = ({ resId, resType, type }: IWidget) => {
+  const [data, setData] = useState<ILikeData[]>();
+  useEffect(() => {
+    if (!resId) {
+      return;
+    }
+    const url = `/v2/like?view=target&target_id=${resId}&type=${type}`;
+    console.info("api request", url);
+    get<ILikeListResponse>(url).then((json) => {
+      console.info("api response", json);
+      if (json.ok) {
+        setData(json.data.rows);
+      }
+    });
+  }, [resId, type]);
+  return (
+    <Space>
+      <Popover trigger={"click"} content={<WatchList data={data} />}>
+        <div>
+          {data?.map((item, id) => {
+            return (
+              <span
+                key={id}
+                style={{ display: "inline-block", marginRight: -8 }}
+              >
+                <User {...item.user} showName={false} hidePopover />
+              </span>
+            );
+          })}
+        </div>
+      </Popover>
+      <WatchAddButton
+        resId={resId}
+        resType={resType}
+        data={data}
+        onAdd={(user: ILikeData) => {
+          setData((origin) => {
+            if (origin) {
+              return [...origin, user];
+            } else {
+              return [user];
+            }
+          });
+        }}
+      />
+    </Space>
+  );
+};
+
+export default LikeAvatar;

+ 63 - 0
dashboard-v4/dashboard/src/components/like/WatchAdd.tsx

@@ -0,0 +1,63 @@
+import { useRef } from "react";
+import { ProForm, ProFormInstance } from "@ant-design/pro-components";
+import { PlusOutlined } from "@ant-design/icons";
+
+import { ILikeData, ILikeRequest, ILikeResponse } from "../api/like";
+import UserSelect from "../template/UserSelect";
+import { post } from "../../request";
+import { Button, Divider, Popover } from "antd";
+import WatchList from "./WatchList";
+
+interface IWidget {
+  resId?: string;
+  resType?: string;
+  data?: ILikeData[];
+  onAdd?: (user: ILikeData) => void;
+}
+
+export const WatchAddButton = ({ resId, resType, data, onAdd }: IWidget) => {
+  return (
+    <Popover
+      trigger={"click"}
+      content={
+        <WatchAdd resId={resId} resType={resType} data={data} onAdd={onAdd} />
+      }
+    >
+      <Button type="text" icon={<PlusOutlined />} />
+    </Popover>
+  );
+};
+const WatchAdd = ({ resId, resType, data, onAdd }: IWidget) => {
+  const formRef = useRef<ProFormInstance>();
+  return (
+    <div>
+      <ProForm<ILikeRequest>
+        formRef={formRef}
+        onFinish={async (values: ILikeRequest) => {
+          if (!resId || !resType) {
+            console.error("no resId or resType", resId, resType);
+            return;
+          }
+          values.type = "watch";
+          values.target_id = resId;
+          values.target_type = resType;
+          const url = `/v2/like`;
+          console.info("watch add api request", url, values);
+          const add = await post<ILikeRequest, ILikeResponse>(url, values);
+          console.debug("watch add api response", add);
+          if (add.ok) {
+            onAdd && onAdd(add.data);
+          }
+        }}
+      >
+        <ProForm.Group>
+          <UserSelect name="user_id" multiple={false} />
+        </ProForm.Group>
+      </ProForm>
+      <Divider />
+      <WatchList data={data} />
+    </div>
+  );
+};
+
+export default WatchAdd;

+ 25 - 0
dashboard-v4/dashboard/src/components/like/WatchList.tsx

@@ -0,0 +1,25 @@
+import { Button, List } from "antd";
+import { DeleteOutlined } from "@ant-design/icons";
+
+import User from "../auth/User";
+import { ILikeData } from "../api/like";
+
+interface IWidget {
+  data?: ILikeData[];
+}
+const WatchList = ({ data }: IWidget) => {
+  return (
+    <List
+      dataSource={data}
+      renderItem={(item) => (
+        <List.Item
+          extra={[<Button type="text" danger icon={<DeleteOutlined />} />]}
+        >
+          <User {...item.user} />
+        </List.Item>
+      )}
+    />
+  );
+};
+
+export default WatchList;