feat: add wxshare
This commit is contained in:
@@ -21,8 +21,9 @@ type TokenResponse struct {
|
||||
}
|
||||
|
||||
// Login
|
||||
// @Router /admin/auth [post]
|
||||
// @Bind body body
|
||||
//
|
||||
// @Router /admin/auth [post]
|
||||
// @Bind body body
|
||||
func (ctl *auth) Login(ctx fiber.Ctx, body *AuthBody) (*TokenResponse, error) {
|
||||
if body.Username == "pl.yang" && body.Password == "Xixi@0202" {
|
||||
claim := ctl.jwt.CreateClaims(jwt.BaseClaims{
|
||||
|
||||
@@ -14,17 +14,19 @@ type medias struct {
|
||||
}
|
||||
|
||||
// List medias
|
||||
// @Router /admin/medias [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
//
|
||||
// @Router /admin/medias [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
||||
cond := models.Medias.BuildConditionWithKey(query.Keyword)
|
||||
return models.Medias.List(ctx.Context(), pagination, cond)
|
||||
}
|
||||
|
||||
// Show media
|
||||
// @Router /admin/medias/:id [get]
|
||||
// @Bind id path
|
||||
//
|
||||
// @Router /admin/medias/:id [get]
|
||||
// @Bind id path
|
||||
func (ctl *medias) Show(ctx fiber.Ctx, id int64) error {
|
||||
media, err := models.Medias.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
@@ -40,8 +42,9 @@ func (ctl *medias) Show(ctx fiber.Ctx, id int64) error {
|
||||
}
|
||||
|
||||
// Delete
|
||||
// @Router /admin/medias/:id [delete]
|
||||
// @Bind id path
|
||||
//
|
||||
// @Router /admin/medias/:id [delete]
|
||||
// @Bind id path
|
||||
func (ctl *medias) Delete(ctx fiber.Ctx, id int64) error {
|
||||
media, err := models.Medias.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
|
||||
@@ -16,9 +16,10 @@ type OrderListQuery struct {
|
||||
type orders struct{}
|
||||
|
||||
// List users
|
||||
// @Router /admin/orders [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
//
|
||||
// @Router /admin/orders [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
func (ctl *orders) List(ctx fiber.Ctx, pagination *requests.Pagination, query *OrderListQuery) (*requests.Pager, error) {
|
||||
cond := models.Orders.BuildConditionWithKey(query.OrderNumber, query.UserID)
|
||||
return models.Orders.List(ctx.Context(), pagination, cond)
|
||||
|
||||
@@ -18,9 +18,10 @@ type ListQuery struct {
|
||||
type posts struct{}
|
||||
|
||||
// List posts
|
||||
// @Router /admin/posts [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
//
|
||||
// @Router /admin/posts [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
||||
cond := models.Posts.BuildConditionWithKey(query.Keyword)
|
||||
pager, err := models.Posts.List(ctx.Context(), pagination, cond)
|
||||
@@ -63,8 +64,9 @@ type PostForm struct {
|
||||
}
|
||||
|
||||
// Create
|
||||
// @Router /admin/posts [post]
|
||||
// @Bind form body
|
||||
//
|
||||
// @Router /admin/posts [post]
|
||||
// @Bind form body
|
||||
func (ctl *posts) Create(ctx fiber.Ctx, form *PostForm) error {
|
||||
post := model.Posts{
|
||||
Title: form.Title,
|
||||
@@ -100,9 +102,10 @@ func (ctl *posts) Create(ctx fiber.Ctx, form *PostForm) error {
|
||||
}
|
||||
|
||||
// Update posts
|
||||
// @Router /admin/posts/:id [put]
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
//
|
||||
// @Router /admin/posts/:id [put]
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (ctl *posts) Update(ctx fiber.Ctx, id int64, form *PostForm) error {
|
||||
oldPost, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
@@ -148,8 +151,9 @@ func (ctl *posts) Update(ctx fiber.Ctx, id int64, form *PostForm) error {
|
||||
}
|
||||
|
||||
// Delete posts
|
||||
// @Router /admin/posts/:id [delete]
|
||||
// @Bind id path
|
||||
//
|
||||
// @Router /admin/posts/:id [delete]
|
||||
// @Bind id path
|
||||
func (ctl *posts) Delete(ctx fiber.Ctx, id int64) error {
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
@@ -172,8 +176,9 @@ type PostItem struct {
|
||||
}
|
||||
|
||||
// Show posts by id
|
||||
// @Router /admin/posts/:id [get]
|
||||
// @Bind id path
|
||||
//
|
||||
// @Router /admin/posts/:id [get]
|
||||
// @Bind id path
|
||||
func (ctl *posts) Show(ctx fiber.Ctx, id int64) (*PostItem, error) {
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
@@ -193,9 +198,10 @@ func (ctl *posts) Show(ctx fiber.Ctx, id int64) (*PostItem, error) {
|
||||
}
|
||||
|
||||
// SendTo
|
||||
// @Router /admin/posts/:id/send-to/:userId [post]
|
||||
// @Bind id path
|
||||
// @Bind userId path
|
||||
//
|
||||
// @Router /admin/posts/:id/send-to/:userId [post]
|
||||
// @Bind id path
|
||||
// @Bind userId path
|
||||
func (ctl *posts) SendTo(ctx fiber.Ctx, id, userId int64) error {
|
||||
if _, err := models.Posts.GetByID(ctx.Context(), id); err != nil {
|
||||
return err
|
||||
|
||||
@@ -22,7 +22,8 @@ type StatisticsResponse struct {
|
||||
}
|
||||
|
||||
// dashboard statistics
|
||||
// @Router /admin/statistics [get]
|
||||
//
|
||||
// @Router /admin/statistics [get]
|
||||
func (s *statistics) statistics(ctx fiber.Ctx) (*StatisticsResponse, error) {
|
||||
statistics := &StatisticsResponse{}
|
||||
|
||||
|
||||
@@ -33,10 +33,11 @@ type PreCheckResp struct {
|
||||
}
|
||||
|
||||
// PreUploadCheck
|
||||
// @Router /admin/uploads/pre-uploaded-check/:md5.:ext [get]
|
||||
// @Bind md5 path
|
||||
// @Bind ext path
|
||||
// @Bind mime query
|
||||
//
|
||||
// @Router /admin/uploads/pre-uploaded-check/:md5.:ext [get]
|
||||
// @Bind md5 path
|
||||
// @Bind ext path
|
||||
// @Bind mime query
|
||||
func (up *uploads) PreUploadCheck(ctx fiber.Ctx, md5, ext, mime string) (*PreCheckResp, error) {
|
||||
_, err := models.Medias.GetByHash(ctx.Context(), md5)
|
||||
if err != nil && errors.Is(err, qrm.ErrNoRows) {
|
||||
@@ -59,8 +60,9 @@ type PostUploadedForm struct {
|
||||
}
|
||||
|
||||
// PostUploadedAction
|
||||
// @Router /admin/uploads/post-uploaded-action [post]
|
||||
// @Bind body body
|
||||
//
|
||||
// @Router /admin/uploads/post-uploaded-action [post]
|
||||
// @Bind body body
|
||||
func (up *uploads) PostUploadedAction(ctx fiber.Ctx, body *PostUploadedForm) error {
|
||||
m, err := models.Medias.GetByHash(ctx.Context(), body.Md5)
|
||||
if err != nil && !errors.Is(err, qrm.ErrNoRows) {
|
||||
|
||||
@@ -16,25 +16,28 @@ type UserListQuery struct {
|
||||
type users struct{}
|
||||
|
||||
// List users
|
||||
// @Router /admin/users [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
//
|
||||
// @Router /admin/users [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
func (ctl *users) List(ctx fiber.Ctx, pagination *requests.Pagination, query *UserListQuery) (*requests.Pager, error) {
|
||||
cond := models.Users.BuildConditionWithKey(query.Keyword)
|
||||
return models.Users.List(ctx.Context(), pagination, cond)
|
||||
}
|
||||
|
||||
// Show user
|
||||
// @Router /admin/users/:id [get]
|
||||
// @Bind id path
|
||||
//
|
||||
// @Router /admin/users/:id [get]
|
||||
// @Bind id path
|
||||
func (ctl *users) Show(ctx fiber.Ctx, id int64) (*model.Users, error) {
|
||||
return models.Users.GetByID(ctx.Context(), id)
|
||||
}
|
||||
|
||||
// Articles show user bought articles
|
||||
// @Router /admin/users/:id/articles [get]
|
||||
// @Bind id path
|
||||
// @Bind pagination query
|
||||
//
|
||||
// @Router /admin/users/:id/articles [get]
|
||||
// @Bind id path
|
||||
// @Bind pagination query
|
||||
func (ctl *users) Articles(ctx fiber.Ctx, id int64, pagination *requests.Pagination) (*requests.Pager, error) {
|
||||
return models.Posts.Bought(ctx.Context(), id, pagination)
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ type auth struct {
|
||||
jwt *jwt.JWT
|
||||
}
|
||||
|
||||
// @Router /auth/login [get]
|
||||
// @Bind code query
|
||||
// @Bind state query
|
||||
// @Bind redirect query
|
||||
// @Router /auth/login [get]
|
||||
// @Bind code query
|
||||
// @Bind state query
|
||||
// @Bind redirect query
|
||||
func (ctl *auth) Login(ctx fiber.Ctx, code, state, redirect string) error {
|
||||
log.Debugf("code: %s, state: %s", code, state)
|
||||
|
||||
@@ -100,7 +100,7 @@ func (ctl *auth) Login(ctx fiber.Ctx, code, state, redirect string) error {
|
||||
}
|
||||
|
||||
// @Router /auth/wechat [get]
|
||||
// @Bind redirect query
|
||||
// @Bind redirect query
|
||||
func (ctl *auth) Wechat(ctx fiber.Ctx, redirect string) error {
|
||||
log.Debugf("%s, query: %v", ctx.OriginalURL(), ctx.Queries())
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ type pays struct {
|
||||
}
|
||||
|
||||
// Callback
|
||||
// @Router /pay/callback/:channel [get]
|
||||
// @Bind channel path
|
||||
//
|
||||
// @Router /pay/callback/:channel [get]
|
||||
// @Bind channel path
|
||||
func (ctl *pays) Callback(ctx fiber.Ctx, channel string) error {
|
||||
log := log.WithField("method", "pays.Callback")
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ type posts struct {
|
||||
}
|
||||
|
||||
// List posts
|
||||
// @Router /posts [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
// @Bind user local
|
||||
//
|
||||
// @Router /posts [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
// @Bind user local
|
||||
func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery, user *model.Users) (*requests.Pager, error) {
|
||||
log.Infof("ok", pagination, query.Keyword, user.ID)
|
||||
|
||||
@@ -99,9 +100,10 @@ type PostItem struct {
|
||||
}
|
||||
|
||||
// Show
|
||||
// @Router /posts/:id/show [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
//
|
||||
// @Router /posts/:id/show [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
func (ctl *posts) Show(ctx fiber.Ctx, id int64, user *model.Users) (*PostItem, error) {
|
||||
log.Infof("Fetching post with ID: %d", id)
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
@@ -148,9 +150,10 @@ type PlayUrl struct {
|
||||
}
|
||||
|
||||
// Play
|
||||
// @Router /posts/:id/play [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
//
|
||||
// @Router /posts/:id/play [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
func (ctl *posts) Play(ctx fiber.Ctx, id int64, user *model.Users) (*PlayUrl, error) {
|
||||
log.Infof("Fetching play URL for post ID: %d", id)
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
@@ -181,10 +184,11 @@ func (ctl *posts) Play(ctx fiber.Ctx, id int64, user *model.Users) (*PlayUrl, er
|
||||
}
|
||||
|
||||
// Mine posts
|
||||
// @Router /posts/mine [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
// @Bind user local
|
||||
//
|
||||
// @Router /posts/mine [get]
|
||||
// @Bind pagination query
|
||||
// @Bind query query
|
||||
// @Bind user local
|
||||
func (ctl *posts) Mine(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery, user *model.Users) (*requests.Pager, error) {
|
||||
log.Infof("Fetching posts for user with pagination: %+v and keyword: %v", pagination, query.Keyword)
|
||||
|
||||
@@ -236,9 +240,10 @@ func (ctl *posts) Mine(ctx fiber.Ctx, pagination *requests.Pagination, query *Li
|
||||
}
|
||||
|
||||
// Buy
|
||||
// @Router /posts/:id/buy [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
//
|
||||
// @Router /posts/:id/buy [get]
|
||||
// @Bind id path
|
||||
// @Bind user local
|
||||
func (ctl *posts) Buy(ctx fiber.Ctx, id int64, user *model.Users) (*wechat.JSAPIPayParams, error) {
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
|
||||
@@ -58,12 +58,14 @@ func Provide(opts ...opt.Option) error {
|
||||
pays *pays,
|
||||
posts *posts,
|
||||
users *users,
|
||||
wechats *wechats,
|
||||
) (contracts.HttpRoute, error) {
|
||||
obj := &Routes{
|
||||
auth: auth,
|
||||
pays: pays,
|
||||
posts: posts,
|
||||
users: users,
|
||||
auth: auth,
|
||||
pays: pays,
|
||||
posts: posts,
|
||||
users: users,
|
||||
wechats: wechats,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -14,11 +14,12 @@ import (
|
||||
|
||||
// @provider contracts.HttpRoute atom.GroupRoutes
|
||||
type Routes struct {
|
||||
log *log.Entry `inject:"false"`
|
||||
auth *auth
|
||||
pays *pays
|
||||
posts *posts
|
||||
users *users
|
||||
log *log.Entry `inject:"false"`
|
||||
auth *auth
|
||||
pays *pays
|
||||
posts *posts
|
||||
users *users
|
||||
wechats *wechats
|
||||
}
|
||||
|
||||
func (r *Routes) Prepare() error {
|
||||
@@ -95,4 +96,11 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Body[ProfileForm]("form"),
|
||||
))
|
||||
|
||||
// 注册路由组: wechats
|
||||
router.Get("/wechats/js-sdk", DataFunc2(
|
||||
r.wechats.GetJsSDK,
|
||||
QueryParam[string]("url"),
|
||||
Local[*model.Users]("user"),
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ type UserInfo struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
// @Router /users/profile [get]
|
||||
// @Bind user local
|
||||
// @Router /users/profile [get]
|
||||
// @Bind user local
|
||||
func (ctl *users) Profile(ctx fiber.Ctx, user *model.Users) (*UserInfo, error) {
|
||||
return &UserInfo{
|
||||
ID: user.ID,
|
||||
@@ -34,9 +34,10 @@ type ProfileForm struct {
|
||||
}
|
||||
|
||||
// Update
|
||||
// @Router /users/username [put]
|
||||
// @Bind user local
|
||||
// @Bind form body
|
||||
//
|
||||
// @Router /users/username [put]
|
||||
// @Bind user local
|
||||
// @Bind form body
|
||||
func (ctl *users) Update(ctx fiber.Ctx, user *model.Users, form *ProfileForm) error {
|
||||
username := strings.TrimSpace(form.Username)
|
||||
if len([]rune(username)) > 12 {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"quyun/database/schemas/public/model"
|
||||
"quyun/providers/wechat"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type wechats struct {
|
||||
wechat *wechat.Client
|
||||
}
|
||||
|
||||
// @Router /wechat/js-ticket [get]
|
||||
// @Bind user local
|
||||
func (ctl *wechats) GetTicket(ctx fiber.Ctx, user *model.Users) (string, error) {
|
||||
return ctl.wechat.GetJSTicket(user.AuthToken.Data.AccessToken)
|
||||
}
|
||||
21
backend/app/http/wechats.go
Normal file
21
backend/app/http/wechats.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"quyun/database/schemas/public/model"
|
||||
"quyun/providers/wechat"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type wechats struct {
|
||||
wechat *wechat.Client
|
||||
}
|
||||
|
||||
// GetJsSDK
|
||||
// @Router /wechats/js-sdk [get]
|
||||
// @Bind url query
|
||||
// @Bind user local
|
||||
func (ctl *wechats) GetJsSDK(ctx fiber.Ctx, url string, user *model.Users) (*wechat.JsSDK, error) {
|
||||
return ctl.wechat.GetJsSDK(user.AuthToken.Data.StableAccessToken, url)
|
||||
}
|
||||
@@ -9,20 +9,20 @@ import (
|
||||
"go.ipao.vip/atom"
|
||||
)
|
||||
|
||||
// @title ApiDoc
|
||||
// @version 1.0
|
||||
// @description This is a sample server celler server.
|
||||
// @termsOfService http://swagger.io/terms/
|
||||
// @contact.name UserName
|
||||
// @contact.url http://www.swagger.io/support
|
||||
// @contact.email support@swagger.io
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
// @host localhost:8080
|
||||
// @BasePath /api/v1
|
||||
// @securityDefinitions.basic BasicAuth
|
||||
// @externalDocs.description OpenAPI
|
||||
// @externalDocs.url https://swagger.io/resources/open-api/
|
||||
// @title ApiDoc
|
||||
// @version 1.0
|
||||
// @description This is a sample server celler server.
|
||||
// @termsOfService http://swagger.io/terms/
|
||||
// @contact.name UserName
|
||||
// @contact.url http://www.swagger.io/support
|
||||
// @contact.email support@swagger.io
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
// @host localhost:8080
|
||||
// @BasePath /api/v1
|
||||
// @securityDefinitions.basic BasicAuth
|
||||
// @externalDocs.description OpenAPI
|
||||
// @externalDocs.url https://swagger.io/resources/open-api/
|
||||
func main() {
|
||||
opts := []atom.Option{
|
||||
atom.Name("quyun"),
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
package wechat
|
||||
|
||||
import "math/rand"
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// RandomString generate random size string
|
||||
func randomString(size int) (string, error) {
|
||||
func randomString(size int) string {
|
||||
// generate size string [0-9a-zA-Z]
|
||||
const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
b := make([]byte, size)
|
||||
for i := range b {
|
||||
b[i] = chars[rand.Intn(len(chars))]
|
||||
}
|
||||
return string(b), nil
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func hashSha1(input string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(input))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package wechat
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -287,3 +288,32 @@ func (we *Client) GetJSTicket(token string) (string, error) {
|
||||
|
||||
return data.Ticket, nil
|
||||
}
|
||||
|
||||
type JsSDK struct {
|
||||
Debug bool `json:"debug"`
|
||||
AppID string `json:"appId"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
NonceStr string `json:"nonceStr"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
// GetJSTicket
|
||||
func (we *Client) GetJsSDK(token, url string) (*JsSDK, error) {
|
||||
sdk := &JsSDK{
|
||||
Debug: false,
|
||||
AppID: we.appID,
|
||||
Timestamp: time.Now().Unix(),
|
||||
NonceStr: randomString(16),
|
||||
Signature: "",
|
||||
}
|
||||
// get ticket
|
||||
ticket, err := we.GetJSTicket(token)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get wechat ticket failed")
|
||||
}
|
||||
|
||||
input := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s", ticket, sdk.NonceStr, sdk.Timestamp, url)
|
||||
sdk.Signature = hashSha1(input)
|
||||
|
||||
return sdk, nil
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -15,10 +15,13 @@
|
||||
"dplayer": "^1.27.1",
|
||||
"pinia": "^3.0.2",
|
||||
"plyr": "^3.7.8",
|
||||
"sha1": "^1.1.1",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"vue": "^3.5.13",
|
||||
"vue-icons-plus": "^0.1.8",
|
||||
"vue-router": "^4.5.0"
|
||||
"vue-router": "^4.5.0",
|
||||
"wechat-js-sdk": "^1.3.3",
|
||||
"weixin-js-sdk": "^1.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.2",
|
||||
|
||||
11
frontend/wechat/src/api/wechatApi.js
Normal file
11
frontend/wechat/src/api/wechatApi.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import client from './client';
|
||||
|
||||
export const wechatApi = {
|
||||
jsSdk() {
|
||||
return client.get('/wechats/js-sdk', {
|
||||
params: {
|
||||
url: window.location.href.split('#')[0],
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
14
frontend/wechat/src/hooks/useRandom.js
Normal file
14
frontend/wechat/src/hooks/useRandom.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export function useRandom() {
|
||||
function string(size) {
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < size; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return {
|
||||
string,
|
||||
};
|
||||
}
|
||||
80
frontend/wechat/src/hooks/useWxSDK.js
Normal file
80
frontend/wechat/src/hooks/useWxSDK.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import wx from "weixin-js-sdk";
|
||||
|
||||
export function useWxSDK() {
|
||||
/**
|
||||
* 初始化设置
|
||||
*/
|
||||
function initConfig(config) {
|
||||
return new Promise((resolve) => {
|
||||
wx.config({
|
||||
debug: config.debug,
|
||||
appId: config.appId,
|
||||
timestamp: config.timestamp,
|
||||
nonceStr: config.nonceStr,
|
||||
signature: config.signature,
|
||||
jsApiList: [
|
||||
"chooseImage",
|
||||
"uploadImage",
|
||||
"previewImage",
|
||||
"onMenuShareTimeline",
|
||||
"onMenuShareAppMessage",
|
||||
"chooseWXPay",
|
||||
],
|
||||
openTagList: [],
|
||||
});
|
||||
wx.ready(() => {
|
||||
console.log("wx.ready called");
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 设置微信分享 */
|
||||
function setShareInfo(
|
||||
shareInfo,
|
||||
onSuccess = () => { },
|
||||
onCancel = () => { }
|
||||
) {
|
||||
wx.onMenuShareTimeline({
|
||||
title: shareInfo.title, // 分享标题
|
||||
link: shareInfo.link, // 分享链接,可以不是当前页面,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
|
||||
imgUrl: shareInfo.imgUrl,
|
||||
success: function () {
|
||||
// 用户确认分享后执行的回调函数
|
||||
onSuccess();
|
||||
},
|
||||
cancel: function () {
|
||||
onCancel();
|
||||
// 用户取消分享后执行的回调函数
|
||||
},
|
||||
});
|
||||
wx.onMenuShareAppMessage({
|
||||
title: shareInfo.title, // 分享标题
|
||||
desc: shareInfo.desc,
|
||||
link: shareInfo.link, // 分享链接,可以不是当前页面,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
|
||||
imgUrl: shareInfo.imgUrl,
|
||||
type: "link", // 分享类型,music、video或link,不填默认为link
|
||||
success: function (e) {
|
||||
// 用户确认分享后执行的回调函数
|
||||
onSuccess();
|
||||
console.log("分享成功", e);
|
||||
},
|
||||
cancel: function (e) {
|
||||
// 用户取消分享后执行的回调函数
|
||||
onCancel();
|
||||
console.log("分享取消", e);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** 是否是ios微信 */
|
||||
function isiOSWechat() {
|
||||
return window.__wxjs_is_wkwebview;
|
||||
}
|
||||
|
||||
return {
|
||||
initConfig,
|
||||
setShareInfo,
|
||||
isiOSWechat,
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,10 @@ import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { BsChevronLeft } from 'vue-icons-plus/bs'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { postApi } from '../api/postApi'
|
||||
import { wechatApi } from '../api/wechatApi'
|
||||
import { useWxSDK } from '../hooks/useWxSDK'
|
||||
|
||||
const wx = useWxSDK()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const article = ref(null)
|
||||
@@ -90,40 +93,13 @@ const fetchArticle = async () => {
|
||||
article.value = data
|
||||
document.title = article.value.title
|
||||
|
||||
// 定义“分享给朋友”及“分享到QQ”按钮的分享内容
|
||||
const shareContent = {
|
||||
// 调用微信 JS SDK 分享接口
|
||||
wx.setShareInfo({
|
||||
title: data.title,
|
||||
desc: data.content,
|
||||
link: window.location.href,
|
||||
imgUrl: data.head_images[0]
|
||||
}
|
||||
// 调用微信 JS SDK 分享接口
|
||||
if (window.wx) {
|
||||
wx.updateTimelineShareData({
|
||||
title: shareContent.title,
|
||||
link: shareContent.link,
|
||||
imgUrl: shareContent.imgUrl,
|
||||
success: function () {
|
||||
console.log('分享成功')
|
||||
},
|
||||
cancel: function () {
|
||||
console.log('分享取消')
|
||||
}
|
||||
})
|
||||
|
||||
wx.updateAppMessageShareData({
|
||||
title: shareContent.title,
|
||||
desc: shareContent.desc,
|
||||
link: shareContent.link,
|
||||
imgUrl: shareContent.imgUrl,
|
||||
success: function () {
|
||||
console.log('分享成功')
|
||||
},
|
||||
cancel: function () {
|
||||
console.log('分享取消')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch article:', error)
|
||||
alert("加载失败!")
|
||||
@@ -137,6 +113,12 @@ const handleBack = () => {
|
||||
onMounted(async () => {
|
||||
await fetchArticle()
|
||||
initializePlayer()
|
||||
|
||||
wechatApi.jsSdk().then(resp => {
|
||||
wx.initConfig(resp.data)
|
||||
}).catch(error => {
|
||||
console.error('Failed to initialize WeChat SDK:', error)
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user