fix issues

This commit is contained in:
Rogee
2024-09-21 13:52:47 +08:00
parent 5aecfe6379
commit f8a7e87965
13 changed files with 156 additions and 51 deletions

1
.dockerignore Normal file
View File

@@ -0,0 +1 @@
**/node_modules

20
Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM docker.hub.ipao.vip/golang:1.22-alpine as builder
COPY . /app
RUN go env -w GOPROXY=https://go.hub.ipao.vip,direct && \
go env -w GO111MODULE=on && \
cd /app && \
go mod tidy && \
go build -o /app/exporter .
FROM docker.hub.ipao.vip/alpine:3.20
COPY --from=builder /app/exporter /usr/local/bin/exporter
COPY config.yml /root/.exporter.yml
WORKDIR /root
ENTRYPOINT ["/usr/local/bin/exporter"]
CMD [ "serve" ]

View File

@@ -3,4 +3,9 @@ model:
rm -rf ./database rm -rf ./database
jet -dsn=postgresql://postgres:xixi0202@10.1.1.3:5432/telegram_resource?sslmode=disable -path=./database jet -dsn=postgresql://postgres:xixi0202@10.1.1.3:5432/telegram_resource?sslmode=disable -path=./database
# gofumpt -w -l -extra ./database # gofumpt -w -l -extra ./database
.PHONY: docker
docker:
docker build -t docker-af.hub.ipao.vip/rogeecn/tg-exporter:latest .
docker push docker-af.hub.ipao.vip/rogeecn/tg-exporter:latest

18
frontend/dist.go Normal file
View File

@@ -0,0 +1,18 @@
package frontend
import "embed"
// embedded files
//
//go:embed dist/assets/*
var StaticDist embed.FS
// embedded dist/favicon.ico
//
//go:embed dist/favicon.ico
var Favicon []byte
// embedded dist/index.html
//
//go:embed dist/index.html
var IndexPage string

View File

@@ -1,18 +1,25 @@
<template> <template>
<div class="bg-slate-100 border rounded mb-4 p-2 md:mb-8 md:p-4"> <div class="mb-4 md:mb-8 border rounded overflow-hidden" :id="`message-${item.ID}`">
<div v-if="item.Content.length > 0" class="text-wrap font-sans" v-html="processedContent"></div> <div class="bg-slate-100 p-2 md:p-4">
<div v-if="item.Content.length > 0" class="text-wrap font-sans" v-html="processedContent"></div>
<div v-if="item.Media.length > 0" class="mt-2 md:mt-4"> <div v-if="item.Media.length > 0" class="mt-2 md:mt-4">
<div class="medias grid grid-cols-3 gap-2 md:gap-4"> <div class="medias grid grid-cols-3 gap-2 md:gap-4">
<template v-for="media in item.Media" :key="media.id"> <template v-for="media in item.Media" :key="media.id">
<MediaItem :media="media" :channel="item.ChannelID" /> <MediaItem :media="media" :channel="item.ChannelID" />
</template> </template>
</div>
</div> </div>
</div> </div>
<div class="grid grid-cols-2">
<button class="py-2 bg-slate-100 hover:bg-slate-50 text-center">Like</button>
<button class="py-2 bg-slate-100 hover:bg-slate-50 text-center text-red-600" @click="delMessage()">Delete</button>
</div>
</div> </div>
</template> </template>
<script> <script>
import { deleteMessage } from "@/services/messages";
import { computed, defineComponent } from "vue"; import { computed, defineComponent } from "vue";
import MediaItem from "./MediaItem.vue"; import MediaItem from "./MediaItem.vue";
@@ -21,6 +28,7 @@ function nl2br(str, is_xhtml) {
return (str + "").replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1" + breakTag + "$2"); return (str + "").replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1" + breakTag + "$2");
} }
export default defineComponent({ export default defineComponent({
components: { components: {
MediaItem, MediaItem,
@@ -35,9 +43,36 @@ export default defineComponent({
return nl2br(content, false); return nl2br(content, false);
}); });
const delMessage = async () => {
console.log("delMessage")
if (!confirm("Are you sure?")) {
return;
}
const itemId = props.item.ID
await deleteMessage(itemId);
// delete dom id #message-{{ item.ID }}
console.log("delete", `message-${itemId}`);
const messageEle = document.getElementById(`message-${itemId}`);
if (messageEle) {
// remove with animation
messageEle.style.transition = "height 0.5s";
messageEle.style.height = "0px";
messageEle.style.border = "0px";
messageEle.style.margin = "0px";
setTimeout(() => {
messageEle.remove();
}, 500);
}
};
return { return {
item: props.item, item: props.item,
processedContent, processedContent,
delMessage,
}; };
}, },
}); });

View File

@@ -1,5 +1,6 @@
<template> <template>
<img :src="photoSrc()" class="max-w-full h-full max-h-full" loading="lazy" decoding="async" @click="openPreview" /> <img :src="photoSrc()" @click="openPreview" decoding="async" loading="lazy"
class="w-full max-w-full h-full max-h-full" />
<div v-if="isPreviewVisible" class="modal" @click="closePreview"> <div v-if="isPreviewVisible" class="modal" @click="closePreview">
<img :src="photoSrc()" alt="Preview" class="preview-image" /> <img :src="photoSrc()" alt="Preview" class="preview-image" />
</div> </div>

View File

@@ -10,15 +10,20 @@ const router = createRouter({
component: () => import('@/views/Home.vue'), component: () => import('@/views/Home.vue'),
}, },
{ {
path: '/favorites', path: '/favorites/:offset(\d+)?',
name: 'favorites', name: 'favorite-messages',
component: () => import('@/views/FavoriteMessages.vue'), component: () => import('@/views/FavoriteMessages.vue'),
}, },
{ {
path: '/channels/:channel/messages', path: '/channels/:channel/messages/:offset(\d+)?',
name: 'channel-messages', name: 'channel-messages',
component: () => import('@/views/ChannelMessages.vue'), component: () => import('@/views/ChannelMessages.vue'),
}, },
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: import('@/views/NotFound.vue'),
},
] ]
}) })

View File

@@ -36,3 +36,10 @@ export async function getFavoriteMessages(params) {
const resp = await http.get(`/favorites`, { params }); const resp = await http.get(`/favorites`, { params });
return processResponseMessage(resp.data); return processResponseMessage(resp.data);
} }
export async function deleteMessage(messageId) {
// return mock('messages', processResponseMessage)
const resp = await http.delete(`/messages/${messageId}`)
return resp.data;
}

View File

@@ -16,16 +16,31 @@ import ListItem from "@/components/ListItem.vue";
import { getChannel } from "@/services/channels"; import { getChannel } from "@/services/channels";
import { getChannelMessages } from "@/services/messages"; import { getChannelMessages } from "@/services/messages";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute, useRouter } from "vue-router";
const route = useRoute(); const route = useRoute();
const router = useRouter();
const channel = ref({}); const channel = ref({});
const messages = ref([]); const messages = ref([]);
const loadMore = async () => { const loadMore = async () => {
const items = await getChannelMessages(route.params.channel, { offset: messages.value[messages.value.length - 1].ID }); // router goto next page
messages.value.push(...items); // offset is last message ID
const offset = messages.value[messages.value.length - 1].ID
router.push({
name: "channel-messages",
params: {
channel: route.params.channel,
offset: offset,
},
});
messages.value = await getChannelMessages(route.params.channel, { offset: offset });
console.log("messages", messages.value);
// page scroll to top with animation
window.scrollTo({ top: 0, behavior: "smooth" });
} }
onMounted(async () => { onMounted(async () => {
@@ -34,7 +49,7 @@ onMounted(async () => {
console.log("channel", channel.value); console.log("channel", channel.value);
// get channel messages // get channel messages
messages.value = await getChannelMessages(route.params.channel); messages.value = await getChannelMessages(route.params.channel, { offset: route.params.offset });
console.log("messages", messages.value); console.log("messages", messages.value);
}); });
</script> </script>

View File

@@ -17,15 +17,31 @@
import ListItem from "@/components/ListItem.vue"; import ListItem from "@/components/ListItem.vue";
import { getFavoriteMessages } from "@/services/messages"; import { getFavoriteMessages } from "@/services/messages";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const messages = ref([]); const messages = ref([]);
const loadMore = async () => { const loadMore = async () => {
const items = await getChannelMessages(route.params.channel, { offset: messages.value[messages.value.length - 1].ID }); // router goto next page
messages.value.push(...items); // offset is last message ID
const offset = messages.value[messages.value.length - 1].ID
router.push({
name: "favorite-messages",
params: {
channel: route.params.channel,
offset: offset,
},
});
messages.value = await getFavoriteMessages({ offset: offset });
console.log("messages", messages.value);
// page scroll to top with animation
window.scrollTo({ top: 0, behavior: "smooth" });
} }
onMounted(async () => { onMounted(async () => {
messages.value = await getFavoriteMessages(); messages.value = await getFavoriteMessages({ offset: route.params.offset });
}); });
</script> </script>

View File

@@ -0,0 +1,3 @@
<template>
<h1>404 NotFound</h1>
</template>

View File

@@ -1,25 +0,0 @@
<template>
<div class="flex flex-col space-y-3">
<ListItem v-for="item in items" :key="item.id" :item="item" />
</div>
</template>
<script setup lang="ts">
import { PostItem } from '@/types'
import { onMounted, ref } from 'vue'
import ListItem from '../components/ListItem.vue'
import data from '../data'
import { } from
const items = ref<PostItem[]>([])
onMounted(() => {
items.value = [
{
id: 1,
content: "Hello Man\nHow are you doing",
medias: data,
},
]
})
</script>

View File

@@ -7,7 +7,7 @@ import (
"exporter/database/telegram_resource/public/model" "exporter/database/telegram_resource/public/model"
"exporter/database/telegram_resource/public/table" "exporter/database/telegram_resource/public/table"
"exporter/frontend/dist" "exporter/frontend"
. "github.com/go-jet/jet/v2/postgres" . "github.com/go-jet/jet/v2/postgres"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
@@ -42,21 +42,22 @@ func serveCmd(cmd *cobra.Command, args []string) error {
app.Static("/medias", "/share/telegram/outputs") app.Static("/medias", "/share/telegram/outputs")
app.Use(favicon.New(favicon.Config{ app.Use(favicon.New(favicon.Config{
Data: dist.Favicon, Data: frontend.Favicon,
})) }))
app.Use("/assets", filesystem.New(filesystem.Config{ app.Use("/assets", filesystem.New(filesystem.Config{
Root: http.FS(dist.StaticDist), Root: http.FS(frontend.StaticDist),
PathPrefix: "assets", PathPrefix: "dist/assets",
})) }))
// Initialize default config // Initialize default config
app.Use(recover.New()) app.Use(recover.New())
app.Get("/", func(c *fiber.Ctx) error { indexFunc := func(c *fiber.Ctx) error {
c.Context().SetContentType("text/html") c.Context().SetContentType("text/html")
return c.SendString(dist.IndexPage) return c.SendString(frontend.IndexPage)
}) }
app.Get("/", indexFunc)
group := app.Group("/api") group := app.Group("/api")
@@ -202,5 +203,8 @@ func serveCmd(cmd *cobra.Command, args []string) error {
return nil return nil
}) })
// not found route use frontend router
// handle 404
app.Use(indexFunc)
return app.Listen(fmt.Sprintf(":%d", port)) return app.Listen(fmt.Sprintf(":%d", port))
} }