zoujiajian пре 1 година
родитељ
комит
43f9bde134
41 измењених фајлова са 2541 додато и 2 уклоњено
  1. 936 0
      netflix-common/src/main/java/com/cyksj/common/util/DateUtil.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeConfigCategoryMapper.java
  3. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeConfigMapper.java
  4. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserConversationChatMapper.java
  5. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserConversationMapper.java
  6. 20 0
      netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserMapper.java
  7. 45 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeConfig.java
  8. 18 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeConfigCategory.java
  9. 18 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUser.java
  10. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUserConversation.java
  11. 53 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUserConversationChat.java
  12. 23 0
      netflix-dao/src/main/java/com/cyksj/model/gpt/ChatChoice.java
  13. 15 0
      netflix-dao/src/main/java/com/cyksj/model/gpt/ChatCompletionResponse.java
  14. 51 0
      netflix-dao/src/main/java/com/cyksj/model/gpt/Message.java
  15. 47 0
      netflix-dao/src/main/java/com/cyksj/model/request/MiniAiPicturesReq.java
  16. 21 0
      netflix-dao/src/main/java/com/cyksj/model/request/MiniPopularizeCategoryUpdateReq.java
  17. 20 0
      netflix-dao/src/main/java/com/cyksj/model/request/MiniPopularizeConfigReq.java
  18. 51 0
      netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeConfigFrontView.java
  19. 56 0
      netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeConfigView.java
  20. 50 0
      netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeUserConversationImgRecordsView.java
  21. 22 0
      netflix-service/src/main/java/com/cyksj/config/TgMiniConfig.java
  22. 1 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  23. 23 0
      netflix-service/src/main/java/com/cyksj/server/SendMessageUtil.java
  24. 126 0
      netflix-service/src/main/java/com/cyksj/server/SseEmitterServer.java
  25. 135 0
      netflix-service/src/main/java/com/cyksj/server/listener/AbstractStreamListener.java
  26. 79 0
      netflix-service/src/main/java/com/cyksj/server/listener/ConsoleStreamListener.java
  27. 16 0
      netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeCommonService.java
  28. 18 0
      netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeFrontService.java
  29. 10 0
      netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeService.java
  30. 40 0
      netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeCommonServiceImpl.java
  31. 230 0
      netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeFrontServiceImpl.java
  32. 14 0
      netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeServiceImpl.java
  33. 22 1
      netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniServiceImpl.java
  34. 5 0
      netflix-web/pom.xml
  35. 163 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/mini/MiniPopularizeController.java
  36. 91 0
      netflix-web/src/main/java/com/cyksj/web/controller/mini/PopularizeMiniController.java
  37. 37 0
      netflix-web/src/main/java/com/cyksj/web/controller/sse/SseController.java
  38. 0 0
      netflix-web/src/main/resources/application-dev.yml
  39. 0 0
      netflix-web/src/main/resources/application-prd.yml
  40. 6 1
      netflix-web/src/main/resources/application-pre.yml
  41. 5 0
      pom.xml

+ 936 - 0
netflix-common/src/main/java/com/cyksj/common/util/DateUtil.java

@@ -0,0 +1,936 @@
+package com.cyksj.common.util;
+
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+public class DateUtil {
+
+    public static final String ISO_DATE_FORMAT = "yyyyMMdd";
+    public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd";
+    public static String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+    public static String DATETIME_PATTERN_STRING = "HH:mm";
+    public static String DATETIME_HHMMSS = "HH:mm:ss";
+    public static String DATE_PATTERN = "yyyyMMddHHmmss";
+    private static boolean LENIENT_DATE = false;
+    private static Random random = new Random();
+    private static final int ID_BYTES = 10;
+
+    public synchronized static String generateId() {
+        StringBuilder result = new StringBuilder();
+        result.append(System.currentTimeMillis());
+        for (int i = 0; i < ID_BYTES; i++) {
+            result.append(random.nextInt(10));
+        }
+        return result.toString();
+    }
+
+    protected static final float normalizedJulian(float JD) {
+
+        float f = Math.round(JD + 0.5f) - 0.5f;
+
+        return f;
+    }
+
+    public static String getDate() {
+        Date date = new Date();
+        return dateToString(date,"yyyy-MM-dd");
+    }
+
+    public static final Date toDate(float JD) {
+        float Z = (normalizedJulian(JD)) + 0.5f;
+        float W = (int) ((Z - 1867216.25f) / 36524.25f);
+        float X = (int) (W / 4f);
+        float A = Z + 1 + W - X;
+        float B = A + 1524;
+        float C = (int) ((B - 122.1) / 365.25);
+        float D = (int) (365.25f * C);
+        float E = (int) ((B - D) / 30.6001);
+        float F = (int) (30.6001f * E);
+        int day = (int) (B - D - F);
+        int month = (int) (E - 1);
+
+        if (month > 12) {
+            month = month - 12;
+        }
+
+        int year = (int) (C - 4715);
+
+        if (month > 2) {
+            year--;
+        }
+
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month - 1);
+        c.set(Calendar.DATE, day);
+
+        return c.getTime();
+    }
+
+
+    /**
+     * 返回当月最后一天的日期
+     */
+    public static Date getLastDayOfMonth() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DATE, calendar.getMaximum(Calendar.DATE));
+        return calendar.getTime();
+    }
+
+    public static int daysBetween(Date early, Date late) {
+        Calendar c1 = Calendar.getInstance();
+        Calendar c2 = Calendar.getInstance();
+        c1.setTime(early);
+        c2.setTime(late);
+        return daysBetween(c1, c2);
+    }
+
+    public static int daysBetween(Calendar early, Calendar late) {
+        return (int) (toJulian(late) - toJulian(early));
+    }
+
+    public static float toJulian(Calendar c) {
+        int Y = c.get(Calendar.YEAR);
+        int M = c.get(Calendar.MONTH);
+        int D = c.get(Calendar.DATE);
+        int A = Y / 100;
+        int B = A / 4;
+        int C = 2 - A + B;
+        float E = (int) (365.25f * (Y + 4716));
+        float F = (int) (30.6001f * (M + 1));
+        return C + D + E + F - 1524.5f;
+    }
+
+    public static float toJulian(Date date) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        return toJulian(c);
+    }
+
+    public static final String dateIncrease(String isoString, String fmt,
+                                            int field, int amount) {
+
+        try {
+            Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
+                    "GMT"));
+            cal.setTime(stringToDate(isoString, fmt, true));
+            cal.add(field, amount);
+
+            return dateToString(cal.getTime(), fmt);
+
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static final String roll(String isoString, String fmt, int field,
+                                    boolean up) throws ParseException {
+
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
+                "GMT"));
+        cal.setTime(stringToDate(isoString, fmt));
+        cal.roll(field, up);
+
+        return dateToString(cal.getTime(), fmt);
+    }
+
+    public static final String roll(String isoString, int field, boolean up) throws
+            ParseException {
+
+        return roll(isoString, DATETIME_PATTERN, field, up);
+    }
+
+    public static Date stringToDate(String dateText, String format,
+                                    boolean lenient) {
+
+        if (dateText == null) {
+
+            return null;
+        }
+
+        DateFormat df = null;
+
+        try {
+
+            if (format == null) {
+                df = new SimpleDateFormat();
+            } else {
+                df = new SimpleDateFormat(format);
+            }
+
+            // setLenient avoids allowing dates  9/32/2001
+            // which would otherwise parse to 10/2/2001
+            df.setLenient(false);
+
+            return df.parse(dateText);
+        } catch (ParseException e) {
+
+            return null;
+        }
+    }
+
+    public static java.sql.Timestamp getCurrentTimestamp() {
+        return new java.sql.Timestamp(new Date().getTime());
+    }
+
+
+    public static Date stringToDate(String dateString, String format) {
+
+        return stringToDate(dateString, format, LENIENT_DATE);
+    }
+
+    public static Date stringToDate(String dateString) {
+        return stringToDate(dateString, ISO_EXPANDED_DATE_FORMAT, LENIENT_DATE);
+    }
+
+
+    public static String dateToString(Date date, String pattern) {
+
+        if (date == null) {
+
+            return null;
+        }
+
+        try {
+
+            SimpleDateFormat sfDate = new SimpleDateFormat(pattern);
+            sfDate.setLenient(false);
+
+            return sfDate.format(date);
+        } catch (Exception e) {
+
+            return null;
+        }
+    }
+
+    public static String dateToString(Date date) {
+        return dateToString(date, ISO_EXPANDED_DATE_FORMAT);
+    }
+    public static Date getCurrentDateTime() {
+        Calendar calNow = Calendar.getInstance();
+        return calNow.getTime();
+    }
+
+    public static String getCurrentDateString(String pattern) {
+        return dateToString(getCurrentDateTime(), pattern);
+    }
+
+    public static String getCurrentDateString() {
+        return dateToString(getCurrentDateTime(), ISO_EXPANDED_DATE_FORMAT);
+    }
+
+    public static String dateToStringWithTime() {
+
+        return dateToString(new Date(), DATETIME_PATTERN);
+    }
+
+    public static String dateToStringWithTime(Date date) {
+
+        return dateToString(date, DATETIME_PATTERN);
+    }
+
+    public static Date dateIncreaseByDay(Date date, int days) {
+
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
+                "GMT"));
+        cal.setTime(date);
+        cal.add(Calendar.DATE, days);
+
+        return cal.getTime();
+    }
+
+    public static Date dateIncreaseByMonth(Date date, int mnt) {
+
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
+                "GMT"));
+        cal.setTime(date);
+        cal.add(Calendar.MONTH, mnt);
+
+        return cal.getTime();
+    }
+
+    public static Date dateIncreaseByYear(Date date, int mnt) {
+
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
+                "GMT"));
+        cal.setTime(date);
+        cal.add(Calendar.YEAR, mnt);
+
+        return cal.getTime();
+    }
+
+
+    public static String dateIncreaseByDay(String date, int days) {
+        return dateIncreaseByDay(date, ISO_DATE_FORMAT, days);
+    }
+
+    public static String dateIncreaseByDay(String date, String fmt, int days) {
+        return dateIncrease(date, fmt, Calendar.DATE, days);
+    }
+
+    public static String stringToString(String src, String srcfmt,
+                                        String desfmt) {
+        return dateToString(stringToDate(src, srcfmt), desfmt);
+    }
+
+    public static String getYear(Date date) {
+        SimpleDateFormat formater = new SimpleDateFormat(
+                "yyyy");
+        return formater.format(date);
+    }
+
+    public static BigDecimal getCurrentTimeAsNumber() {
+        String returnStr = null;
+        SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss");
+        Date date = new Date();
+        returnStr = f.format(date);
+        return new BigDecimal(returnStr);
+    }
+
+    public static BigDecimal getCurrentDateAsNumber() {
+        String returnStr = null;
+        SimpleDateFormat f = new SimpleDateFormat("yyyyMMdd");
+        Date date = new Date();
+        returnStr = f.format(date);
+        return new BigDecimal(returnStr);
+    }
+
+    public static String getMonth(Date date) {
+        SimpleDateFormat formater = new SimpleDateFormat(
+                "MM");
+        return formater.format(date);
+    }
+
+    public static String getDay(Date date) {
+        SimpleDateFormat formater = new SimpleDateFormat(
+                "dd");
+        return formater.format(date);
+    }
+
+    public static String getHour(Date date) {
+        SimpleDateFormat formater = new SimpleDateFormat(
+                "HH");
+        return formater.format(date);
+    }
+
+    public static int getMinsFromDate(Date dt) {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTime(dt);
+        int hour = cal.get(Calendar.HOUR_OF_DAY);
+        int min = cal.get(Calendar.MINUTE);
+        return ((hour * 60) + min);
+    }
+
+    public static Date convertToDate(String str, boolean isExpiry) {
+        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        Date dt = null;
+        try {
+            dt = fmt.parse(str);
+        } catch (ParseException ex) {
+            Calendar cal = Calendar.getInstance();
+            if (isExpiry) {
+                cal.add(Calendar.DAY_OF_MONTH, 1);
+                cal.set(Calendar.HOUR_OF_DAY, 23);
+                cal.set(Calendar.MINUTE, 59);
+            } else {
+                cal.set(Calendar.HOUR_OF_DAY, 0);
+                cal.set(Calendar.MINUTE, 0);
+            }
+            dt = cal.getTime();
+        }
+        return dt;
+    }
+
+    public static Date getEndTime(Date endTime) {
+        int dayMis = 1000 * 60 * 60 * 24;
+        long resultMis = endTime.getTime() + dayMis - 1;
+        return new Date(resultMis);
+
+    }
+
+    public static Date convertToDate(String str) {
+        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+        Date dt = null;
+        try {
+            dt = fmt.parse(str);
+        } catch (ParseException ex) {
+            dt = new Date();
+        }
+        return dt;
+    }
+
+    public static String dateFromat(Date date, int minute) {
+        String dateFormat = null;
+        int year = Integer.parseInt(getYear(date));
+        int month = Integer.parseInt(getMonth(date));
+        int day = Integer.parseInt(getDay(date));
+        int hour = minute / 60;
+        int min = minute % 60;
+        dateFormat = String.valueOf(year)
+                +
+                (month > 9 ? String.valueOf(month) :
+                        "0" + String.valueOf(month))
+                +
+                (day > 9 ? String.valueOf(day) : "0" + String.valueOf(day))
+                + " "
+                +
+                (hour > 9 ? String.valueOf(hour) : "0" + String.valueOf(hour))
+                +
+                (min > 9 ? String.valueOf(min) : "0" + String.valueOf(min))
+                + "00";
+        return dateFormat;
+    }
+
+    public static String sDateFormat() {
+        return new SimpleDateFormat(DATE_PATTERN).format(Calendar.getInstance().getTime());
+    }
+
+    public static boolean checkStringIsDate(String dateStr) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        sdf.setLenient(false);
+        boolean result = true;
+        if (dateStr == null || dateStr.length() == 0) {
+            return false;
+        }
+        try {
+            Date date = sdf.parse(dateStr);
+            return true;
+        } catch (ParseException e) {
+            return false;
+        }
+    }
+
+    public static Date getLastTimeInDay(Date date) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String str = format.format(date);
+        Date tempDate = convertToDate(str);
+        int dayMis = 1000 * 60 * 60 * 24;
+        long curMillisecond = tempDate.getTime();
+        long resultMis = curMillisecond + (dayMis - 1);
+        return new Date(resultMis);
+    }
+
+    public static Date getFirstTimeInDay(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        Date zero = calendar.getTime();
+        return zero;
+    }
+    public static int getMonthBetweenDate(Date startDate, Date endDate) {
+        int result = 0;
+        try {
+            String date1 = startDate.toString();
+            String date2 = endDate.toString();
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+            Calendar c1 = Calendar.getInstance();
+            Calendar c2 = Calendar.getInstance();
+            c1.setTime(sdf.parse(date1));
+            c2.setTime(sdf.parse(date2));
+            result = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR) * 12;
+        } catch (Exception ex) {
+            result = -1;
+            System.out.println(ex.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 获取当前日期上一月第一天00:00:00时间
+     * @return
+     */
+    public static Date getPreviousMonthFirstDay() {
+        //获取当前日期
+        Calendar calendar = Calendar.getInstance();
+        //获取当前日期上一个月月份
+        calendar.add(Calendar.MONTH, -1);
+        //设置为1号,当前日期既为本月第一天
+        calendar.set(Calendar.DAY_OF_MONTH,1);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        //获取计算结果当天的第一秒时间
+        return DateUtil.convertToDate(sdf.format(getFirstTimeInDay(calendar.getTime())));
+    }
+
+    /**
+     * 获取当前日期上一月最后一天23:59:59时间
+     * @return
+     */
+    public static Date getPreviousMonthLastDayTime() {
+        //获取当前日期
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH,0);
+        return getLastTimeInDay(calendar.getTime());
+    }
+
+    /**
+     * 获取当前日期上一月最后一天日期
+     * @return
+     */
+    public static int getPreviousMonthLastDay() {
+        //获取当前日期
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH,0);
+        return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * 获取当前日期前一天开始时间00:00:00
+     * @return
+     */
+    public static Date getPreviousDayFirstTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.DATE,-1);
+        return getFirstTimeInDay(calendar.getTime());
+    }
+
+    public static Date getNextDayFirstTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.DATE,1);
+        return getFirstTimeInDay(calendar.getTime());
+    }
+    public static Date getPreviousDayLastTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.DATE,-1);
+        return getLastTimeInDay(calendar.getTime());
+    }
+
+    /**
+     * 获取当前月第一天00:00:00
+     * @return
+     */
+    public static Date getMonthFirstTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        //将小时至0
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        //将分钟至0
+        calendar.set(Calendar.MINUTE, 0);
+        //将秒至0
+        calendar.set(Calendar.SECOND,0);
+        //将毫秒至0
+        calendar.set(Calendar.MILLISECOND, 0);
+        //获得当前月第一天
+        return  calendar.getTime();
+    }
+
+    /**
+     * 获取当前月最后一天23:59:59
+     * @return
+     */
+    public static Date getMonthLastTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        //将小时至0
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        //将分钟至0
+        calendar.set(Calendar.MINUTE, 0);
+        //将秒至0
+        calendar.set(Calendar.SECOND,0);
+        //将毫秒至0
+        calendar.set(Calendar.MILLISECOND, 0);
+        //将当前月加1;
+        calendar.add(Calendar.MONTH, 1);
+        //在当前月的下一月基础上减去1秒
+        calendar.add(Calendar.SECOND, -1);
+        //获得当前月最后一天
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取当年的第一天
+     * @return
+     */
+    public static Date getCurrYearFirst(){
+        Calendar currCal=Calendar.getInstance();
+        int currentYear = currCal.get(Calendar.YEAR);
+        return getYearFirst(currentYear);
+    }
+
+    /**
+     * 获取当年的最后一天
+     * @return
+     */
+    public static Date getCurrYearLast(){
+        Calendar currCal=Calendar.getInstance();
+        int currentYear = currCal.get(Calendar.YEAR);
+        return getYearLast(currentYear);
+    }
+
+    /**
+     * 获取某年第一天日期
+     * @param year 年份
+     * @return Date
+     */
+    public static Date getYearFirst(int year){
+        Calendar calendar = Calendar.getInstance();
+        calendar.clear();
+        calendar.set(Calendar.YEAR, year);
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取某年最后一天日期
+     * @param year 年份
+     * @return Date
+     */
+    public static Date getYearLast(int year){
+        Calendar calendar = Calendar.getInstance();
+        calendar.clear();
+        calendar.set(Calendar.YEAR, year);
+        calendar.roll(Calendar.DAY_OF_YEAR, -1);
+        return calendar.getTime();
+    }
+
+    /**
+     * 判断当前是星期几
+     * @param dt
+     * @return
+     */
+    public static String getWeekOfDate(Date dt) {
+            String[] weekDays = { "sunday" ,"monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(dt);
+            int w = cal.get(Calendar.DAY_OF_WEEK)-1;
+            if (w < 0){
+                w = 0;
+            }
+            return weekDays[w];
+
+    }
+
+    /**实现给定某日期,判断是星期几 必须yyyy-MM-dd
+     * @param date
+     * @return
+     */
+    public static String getWeekday(String date){
+        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
+        Locale localeCN = Locale.SIMPLIFIED_CHINESE;
+        SimpleDateFormat sdw = new SimpleDateFormat("E",localeCN);
+        Date d = null;
+        try {
+            d = sd.parse(date);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return sdw.format(d);
+    }
+    /**
+     * 判断时间是否在时间段内
+     * @param beginTime
+     * @param endTime
+     * @return
+     */
+    public static boolean belongCalendar(String beginTime, String endTime) throws ParseException {
+        //格式化日期
+        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
+        Calendar date = Calendar.getInstance();
+        date.setTime( df.parse(df.format(new Date())));
+        Calendar begin = Calendar.getInstance();
+        begin.setTime(df.parse(beginTime));
+
+        Calendar end = Calendar.getInstance();
+        end.setTime(df.parse(endTime));
+
+        if (date.after(begin) && date.before(end)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    public static String dateToStringHHmmss(Date date) {
+
+        return dateToString(date, DATETIME_HHMMSS);
+    }
+    /**
+     * 获取某一时间段特定星期几的日期
+     * @param dateFrom 开始时间
+     * @param dateEnd 结束时间
+     * @param weekDays 星期
+     * @return 返回时间数组
+     */
+    public static String[] getDates(String dateFrom, String dateEnd, String weekDays) {
+        long time = 1l;
+        long perDayMilSec = 24 * 60 * 60 * 1000;
+        List<String> dateList = new ArrayList<String>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        //需要查询的星期系数
+        String strWeekNumber = weekForNum(weekDays);
+        try {
+            dateFrom = sdf.format(sdf.parse(dateFrom).getTime() - perDayMilSec);
+            while (true) {
+                time = sdf.parse(dateFrom).getTime();
+                time = time + perDayMilSec;
+                Date date = new Date(time);
+                dateFrom = sdf.format(date);
+                if (dateFrom.compareTo(dateEnd) <= 0) {
+                    //查询的某一时间的星期系数
+                    Integer weekDay = dayForWeek(date);
+                    //判断当期日期的星期系数是否是需要查询的
+                    if (strWeekNumber.contains(weekDay.toString())) {
+                        dateList.add(dateFrom);
+                    }
+                } else {
+                    break;
+                }
+            }
+        } catch (ParseException e1) {
+            e1.printStackTrace();
+        }
+        String[] dateArray = new String[dateList.size()];
+        dateList.toArray(dateArray);
+        return dateArray;
+    }
+
+    /**等到当期时间的周系数。星期日:1,星期一:2,星期二:3,星期三:4,星期四:5,星期五:6,星期六:7,星期日
+     * @param date
+     * @return
+     */
+    public static Integer dayForWeek(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return calendar.get(Calendar.DAY_OF_WEEK);
+    }
+
+    /**
+     * 得到对应星期的系数  星期日:1,星期一:2,星期二:3,星期三:4,星期四:5,星期五:6,星期六:7
+     * @param weekDays 星期格式  星期一|星期二
+     */
+    public static String weekForNum(String weekDays){
+        //返回结果为组合的星期系数
+        String weekNumber = "";
+        //解析传入的星期
+        //多个星期数
+        if(weekDays.contains("|")){
+            String []strWeeks = weekDays.split("\\|");
+            for(int i=0;i<strWeeks.length;i++){
+                weekNumber = weekNumber + "" + getWeekNum(strWeeks[i]).toString();
+            }
+        }else{//一个星期数
+            weekNumber = getWeekNum(weekDays).toString();
+        }
+
+        return weekNumber;
+
+    }
+
+    /**将星期转换为对应的系数  星期日:1,星期一:2,星期二:3,星期三:4,星期四:5,星期五:6,星期六:7,星期日
+     * @param strWeek
+     * @return
+     */
+    public static Integer getWeekNum(String strWeek){
+        //默认为星期日
+        Integer number = 1;
+        if("星期日".equals(strWeek)){
+            number = 1;
+        }else if("星期一".equals(strWeek)){
+            number = 2;
+        }else if("星期二".equals(strWeek)){
+            number = 3;
+        }else if("星期三".equals(strWeek)){
+            number = 4;
+        }else if("星期四".equals(strWeek)){
+            number = 5;
+        }else if("星期五".equals(strWeek)){
+            number = 6;
+        }else if("星期六".equals(strWeek)){
+            number = 7;
+        }
+        return number;
+    }
+    public static boolean sameDate(Date d1, Date d2) throws ParseException {
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        if(df.parse(DateUtil.dateToString(d1)).getTime() > df.parse(DateUtil.dateToString(d2)).getTime()){
+           return true;
+        }else {
+            return false;
+        }
+    }
+    public static boolean compareNewDate(Date date,String time) throws ParseException {
+        SimpleDateFormat sdfd =new SimpleDateFormat("yyy-MM-dd ");
+        String s = sdfd.format(new Date());
+        int code = date.compareTo(sdfd.parse(s));
+        if(code <= 0){
+            return compareNewTime(time);
+        }
+        return true;
+
+    }
+    public static boolean compareNewTime(String time) {
+        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
+        int code = df.format(new Date()).compareTo(time);
+        return (code < 0);
+
+    }
+    /**
+     * 计算年纪
+     * @param birthDay
+     * @return
+     * @throws ParseException
+     */
+    public static int getAgeByBirth(Date birthDay) {
+        try {
+            int age = 0;
+            Calendar cal = Calendar.getInstance();
+            //出生日期晚于当前时间,无法计算
+            if (cal.before(birthDay)) {
+                throw new IllegalArgumentException(
+                        "The birthDay is before Now.It's unbelievable!");
+            }
+            //当前年份
+            int yearNow = cal.get(Calendar.YEAR);
+            //当前月份
+            int monthNow = cal.get(Calendar.MONTH);
+            //当前日期
+            int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
+            cal.setTime(birthDay);
+            int yearBirth = cal.get(Calendar.YEAR);
+            int monthBirth = cal.get(Calendar.MONTH);
+            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
+            //计算整岁数
+            age = yearNow - yearBirth;
+            if (monthNow <= monthBirth) {
+                if (monthNow == monthBirth) {
+                    //当前日期在生日之前,年龄减一
+                    if (dayOfMonthNow < dayOfMonthBirth) {age--;}
+                } else {
+                    //当前月份在生日之前,年龄减一
+                    age--;
+                }
+            }
+            if(age == 0){
+                return  age + 1;
+            }
+            return  age;
+        } catch (Exception ex) {
+            System.out.println(ex.getMessage());
+            return 0;
+        }
+    }
+    public static boolean dateCompareNowDate(String date) throws ParseException {
+        Date nowDate = new Date();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
+        Date d = sdf.parse(date);
+        boolean flag = d.before(nowDate);
+        if(flag){
+            System.out.print("早于今天") ;
+        }else{
+            System.out.print("晚于今天") ;
+        }
+        return flag;
+    }
+    public static String timeSlot(int code,int number,Date date){
+        StringBuilder stringBuilder = new StringBuilder();
+        Calendar ca = Calendar.getInstance();
+        ca.setTime(date);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        switch (code){
+            case 1:
+                //减年
+                ca.add(Calendar.YEAR, -number);
+                break;
+            case 2:
+                //减月
+                ca.add(Calendar.MONTH,-number);
+                break;
+            case 3:
+                //减天
+                ca.add(Calendar.DATE,-number);
+                break;
+            case 4:
+                //加天
+                ca.add(Calendar.DATE,+number);
+                break;
+            default:
+        }
+        stringBuilder.append(sdf.format(ca.getTime()));
+        stringBuilder.append("~");
+        stringBuilder.append(sdf.format(date));
+        return stringBuilder.toString();
+    }
+    public static Integer BirthdayDays(String clidate) throws ParseException {
+        SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
+        // 存今天
+        Calendar cToday = Calendar.getInstance();
+        // 存生日
+        Calendar cBirth = Calendar.getInstance();
+        // 设置生日
+        cBirth.setTime(myFormatter.parse(clidate));
+        // 修改为本年
+        cBirth.set(Calendar.YEAR, cToday.get(Calendar.YEAR));
+        int days;
+        if (cBirth.get(Calendar.DAY_OF_YEAR) < cToday.get(Calendar.DAY_OF_YEAR)) {
+            // 生日已经过了,要算明年的了
+            days = cToday.getActualMaximum(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
+            days += cBirth.get(Calendar.DAY_OF_YEAR);
+        } else {
+            // 生日还没过
+            days = cBirth.get(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
+        }
+        // 输出结果
+        if (days == 0) {
+            return 0;
+        } else {
+            return days;
+        }
+    }
+
+    /**
+     * 月份加减
+     * @param date
+     * @return
+     * @throws ParseException
+     */
+    public static String  increaseDay(String date,Integer code) throws ParseException {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date dt = format.parse(date);
+        Calendar rightNow = Calendar.getInstance();
+        rightNow.setTime(dt);
+        rightNow.add(Calendar.DAY_OF_MONTH, code);
+        Date newDate = rightNow.getTime();
+        return format.format(newDate);
+    }
+
+    public static Date getSubscribeTime(Long subscribeTime) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String date = sdf.format(new Date(subscribeTime*1000L));
+        return DateUtil.stringToDate(date,DATETIME_PATTERN);
+    }
+    public static boolean isValidDate(String str) {
+        boolean convertSuccess = true;
+        // 指定日期格式为四位年/两位月份/两位日期,注意yyyy/MM/dd区分大小写;
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            // 设置lenient为false.
+            // 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
+            format.setLenient(false);
+            format.parse(str);
+        } catch (Exception e) {
+            // e.printStackTrace();
+            // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
+            convertSuccess = false;
+        }
+        return convertSuccess;
+    }
+    public static String getLocalDateTimeNow(){
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDateTime localDateTime = LocalDateTime.now();
+        return formatter.format(localDateTime);
+    }
+    public static String timestamp2LocalDateTime(Long timeMillis) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime localDateTime = Instant.ofEpochMilli(timeMillis).atZone(zoneId).toLocalDateTime();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        return formatter.format(localDateTime);
+    }
+
+    public static final DateTimeFormatter DFT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeConfigCategoryMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.mini;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MiniPopularizeConfigCategory;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigCategoryMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:46
+ */
+public interface MiniPopularizeConfigCategoryMapper extends BaseMapper<MiniPopularizeConfigCategory> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeConfigMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.mini;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MiniPopularizeConfig;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:25
+ */
+public interface MiniPopularizeConfigMapper extends BaseMapper<MiniPopularizeConfig> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserConversationChatMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.mini;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserConversationChatMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/4/11 17:58
+ */
+public interface MiniPopularizeUserConversationChatMapper extends BaseMapper<MiniPopularizeUserConversationChat> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserConversationMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.mini;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MiniPopularizeUserConversation;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserConversationMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/4/10 16:50
+ */
+public interface MiniPopularizeUserConversationMapper extends BaseMapper<MiniPopularizeUserConversation> {
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/mapper/mini/MiniPopularizeUserMapper.java

@@ -0,0 +1,20 @@
+package com.cyksj.mapper.mini;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MiniPopularizeUser;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/4/10 15:17
+ */
+public interface MiniPopularizeUserMapper extends BaseMapper<MiniPopularizeUser> {
+	@Update("update mini_popularize_user set num = num + #{num} where id = #{id}")
+	int incrNum(@Param("id") Long id, @Param("num") Integer num);
+
+	@Update("update mini_popularize_user set num = num - #{num} where id = #{id} and num = #{userNum} and num > 0")
+	int decLumaNum(@Param("id") Long id, @Param("num") Integer num, @Param("userNum") Integer userNum);
+}

+ 45 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeConfig.java

@@ -0,0 +1,45 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfig
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:22
+ */
+@Getter
+@Setter
+public class MiniPopularizeConfig extends BaseEntity{
+	/**
+	 * 配置类型
+	 */
+	private Type type;
+
+	private String img;
+
+	private String tips;
+
+	private Integer sorted;
+
+	private Boolean status;
+
+	/**
+	 * 分类id
+	 */
+	private Long cid;
+
+	@Getter
+	public enum Type{
+		Stype("风格"),
+		Home("首页"),
+		Banner("banner"),
+		;
+		String desc;
+
+		Type(String desc) {
+			this.desc = desc;
+		}
+	}
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeConfigCategory.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigCategory
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:45
+ */
+@Getter
+@Setter
+public class MiniPopularizeConfigCategory extends BaseEntity{
+	private String name;
+
+	private Integer sorted;
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUser.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUser
+ * 创建者: JavaZou
+ * 创建时间:2025/4/9 11:53
+ */
+@Getter
+@Setter
+public class MiniPopularizeUser extends BaseEntity{
+	private Long userId;
+
+	private Integer num;
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUserConversation.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.entity;
+
+import lombok.*;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserConversation
+ * 创建者: JavaZou
+ * 创建时间:2025/4/10 16:49
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class MiniPopularizeUserConversation extends BaseEntity{
+	private String conversationId;
+
+	private String content;
+
+	private Long userId;
+}

+ 53 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MiniPopularizeUserConversationChat.java

@@ -0,0 +1,53 @@
+package com.cyksj.model.entity;
+
+import lombok.*;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserConversationChat
+ * 创建者: JavaZou
+ * 创建时间:2025/4/11 17:56
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class MiniPopularizeUserConversationChat extends BaseEntity{
+	private String conversationId;
+
+	private Long userId;
+
+	private String img;
+
+	private String content;
+
+	private Type type;
+
+	private Status status;
+
+	@Getter
+	public enum Type{
+		image("图像"),
+		text("文本"),
+		;
+		String desc;
+
+		Type(String desc) {
+			this.desc = desc;
+		}
+	}
+
+	@Getter
+	public enum Status{
+		success("成功"),
+		fail("失败"),
+		processing("生成中"),
+		;
+		String desc;
+
+		Status(String desc) {
+			this.desc = desc;
+		}
+	}
+}

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/gpt/ChatChoice.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.gpt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+
+@Data
+public class ChatChoice {
+    private long index;
+    /**
+     * 请求参数stream为true返回是delta
+     */
+    @JsonProperty("delta")
+    private Message delta;
+    /**
+     * 请求参数stream为false返回是message
+     */
+    @JsonProperty("message")
+    private Message message;
+
+    @JsonProperty("finish_reason")
+    private String finishReason;
+}

+ 15 - 0
netflix-dao/src/main/java/com/cyksj/model/gpt/ChatCompletionResponse.java

@@ -0,0 +1,15 @@
+package com.cyksj.model.gpt;
+
+import lombok.Data;
+
+import java.util.List;
+
+
+@Data
+public class ChatCompletionResponse {
+    private String id;
+    private String object;
+    private long created;
+    private String model;
+    private List<ChatChoice> choices;
+}

+ 51 - 0
netflix-dao/src/main/java/com/cyksj/model/gpt/Message.java

@@ -0,0 +1,51 @@
+package com.cyksj.model.gpt;
+
+import com.cyksj.common.util.DateUtil;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.*;
+
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Message {
+    /**
+     * 目前支持三种角色参考官网,进行情景输入:https://platform.openai.com/docs/guides/chat/introduction
+     */
+    private String role;
+    private String content;
+    private String name;
+    private String time;
+
+    public Message(String role, String content) {
+        this.role = role;
+        this.content = content;
+        this.time = DateUtil.getLocalDateTimeNow();
+    }
+
+    public static Message of(String content) {
+        return new Message(Role.USER.getValue(), content);
+    }
+
+    public static Message ofSystem(String content) {
+        return new Message(Role.SYSTEM.getValue(),content);
+    }
+
+    public static Message ofAssistant(String content) {
+        return new Message(Role.ASSISTANT.getValue(), content);
+    }
+    
+    @Getter
+    @AllArgsConstructor
+    public enum Role {
+
+        SYSTEM("system"),
+        USER("user"),
+        ASSISTANT("assistant"),
+        ;
+        private String value;
+    }
+
+}

+ 47 - 0
netflix-dao/src/main/java/com/cyksj/model/request/MiniAiPicturesReq.java

@@ -0,0 +1,47 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniAiPicturesReq
+ * 创建者: JavaZou
+ * 创建时间:2025/4/8 16:52
+ */
+@Getter
+@Setter
+public class MiniAiPicturesReq {
+	/**
+	 * 配置id
+	 */
+	private Long id;
+
+	private Long userId;
+
+	/**
+	 * 提示词
+	 */
+	private String tips;
+
+	/**
+	 * 图片
+	 */
+	private String img;
+
+	/**
+	 * 会话id
+	 */
+	private String conversationId;
+
+	/**
+	 * 上次图片记录id
+	 */
+	private Long chatId;
+
+	/**
+	 * 出图类型
+	 * 默认普通1  2.垫图风格
+	 */
+	private Integer type = 1;
+}

+ 21 - 0
netflix-dao/src/main/java/com/cyksj/model/request/MiniPopularizeCategoryUpdateReq.java

@@ -0,0 +1,21 @@
+package com.cyksj.model.request;
+
+import com.cyksj.model.entity.MiniPopularizeConfigCategory;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeCategoryUpdateReq
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:56
+ */
+@Getter
+@Setter
+public class MiniPopularizeCategoryUpdateReq {
+	private List<MiniPopularizeConfigCategory> categories;
+
+	private List<Long> delIds;
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/request/MiniPopularizeConfigReq.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigReq
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:37
+ */
+@Getter
+@Setter
+public class MiniPopularizeConfigReq {
+	private List<Long> ids;
+
+	private Boolean status;
+}

+ 51 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeConfigFrontView.java

@@ -0,0 +1,51 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.MiniPopularizeConfig;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigFrontView
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 17:46
+ */
+@Getter
+@Setter
+@SearchBean(tables = "mini_popularize_config mpc left join mini_popularize_config_category mc on mc.id = mpc.cid",
+		where = "mpc.status is true")
+public class MiniPopularizeConfigFrontView {
+	@DbField("mpc.id")
+	private Long id;
+
+	@DbField("mpc.cid")
+	private Long cid;
+
+	/**
+	 * 分类
+	 */
+	@DbField("mc.name")
+	private String category;
+
+	/**
+	 * 类型
+	 */
+	@DbField("mpc.type")
+	private MiniPopularizeConfig.Type type;
+
+	@DbField("mpc.img")
+	private String img;
+
+	@DbField("mpc.tips")
+	private String tips;
+
+	@DbField("mpc.sorted")
+	private Integer sorted;
+
+	@DbField("mpc.update_time")
+	private Date updateTime;
+}

+ 56 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeConfigView.java

@@ -0,0 +1,56 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.MiniPopularizeConfig;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeConfigView
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:26
+ */
+@Getter
+@Setter
+@SearchBean(tables = "mini_popularize_config mpc left join mini_popularize_config_category mc on mc.id = mpc.cid")
+public class MiniPopularizeConfigView {
+	@DbField("mpc.id")
+	private Long id;
+
+	@DbField("mpc.cid")
+	private Long cid;
+
+	/**
+	 * 分类
+	 */
+	@DbField("mc.name")
+	private String category;
+
+	/**
+	 * 类型
+	 */
+	@DbField("mpc.type")
+	private MiniPopularizeConfig.Type type;
+
+	@DbField("mpc.img")
+	private String img;
+
+	@DbField("mpc.tips")
+	private String tips;
+
+	@DbField("mpc.sorted")
+	private Integer sorted;
+
+	@DbField("mpc.status")
+	private Boolean status;
+
+	@DbField("mpc.created_time")
+	private Date createdTime;
+
+	@DbField("mpc.update_time")
+	private Date updateTime;
+}

+ 50 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MiniPopularizeUserConversationImgRecordsView.java

@@ -0,0 +1,50 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeUserConversationImgRecordsView
+ * 创建者: JavaZou
+ * 创建时间:2025/4/11 17:26
+ */
+@Getter
+@Setter
+@SearchBean(tables = "mini_popularize_user_conversation mc left join mini_popularize_user_conversation_chat mr on mr.conversation_id = mc.conversation_id",
+		orderBy = "mr.created_time desc")
+public class MiniPopularizeUserConversationImgRecordsView {
+	@DbField("mc.conversation_id")
+	private String conversationId;
+
+	@DbField("mr.id")
+	private Long chatId;
+
+	@DbField("mc.user_id")
+	@JsonIgnore
+	private Long userId;
+
+	@DbField("mr.content")
+	private String content;
+
+	@DbField("mr.img")
+	private String img;
+
+	@DbField("mr.type")
+	private MiniPopularizeUserConversationChat.Type type;
+
+	@DbField("mr.status")
+	private MiniPopularizeUserConversationChat.Status status;
+
+	@DbField("ifnull(mr.created_time,mc.created_time)")
+	private Date createdTime;
+
+	@DbField("ifnull(mr.update_time,mc.update_time)")
+	private Date updateTime;
+}

+ 22 - 0
netflix-service/src/main/java/com/cyksj/config/TgMiniConfig.java

@@ -0,0 +1,22 @@
+package com.cyksj.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: TgMiniConfig
+ * 创建者: JavaZou
+ * 创建时间:2025/4/10 15:28
+ */
+@Configuration
+@ConfigurationProperties(prefix = "tgmini")
+@Getter
+@Setter
+public class TgMiniConfig {
+	private String appId;
+
+	private String secret;
+}

+ 1 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -854,6 +854,7 @@ public class RedisService {
         USER_MIRROR_SHOP_ADVERTISE_CACHE_KEY("user_mirror_shop_advertise_cache_key:", "用户镜像店铺广告缓存key", 60 * 60 * 12),
         NETFLIX_CHANGE_TICKET_KEY("netflix_change_ticket_key:", "奈飞更换车票key", 60l),
         CORP_KF_ACCOUNT_URL("corp_kf_account_url:", "微信客服url:", 60 * 60 * 6),
+        MINI_POPULARIZE_GPT_NUM("mini_popularize_gpt_num:", "推广小程序GPT图像次数", 60 * 60 * 2L),
         ;
 
         private String name;

+ 23 - 0
netflix-service/src/main/java/com/cyksj/server/SendMessageUtil.java

@@ -0,0 +1,23 @@
+package com.cyksj.server;
+
+public class SendMessageUtil {
+
+    public static void sendMessage(Long userId, Object message) {
+        //对话模型
+//        Integer isMobile  = RedisUtil.getCacheObject(CommonConst.USER_CLIENT + userId);
+        Integer isMobile = null;
+        //默认不实时
+        if(null == isMobile){
+            isMobile = 0;
+        }
+        if (isMobile == 1) {
+//            try {
+//                WebSocketServer.sendInfo(userId, message);
+//            } catch (IOException e) {
+//                throw new RuntimeException(e);
+//            }
+        } else {
+            SseEmitterServer.sendMessage(userId, message);
+        }
+    }
+}

+ 126 - 0
netflix-service/src/main/java/com/cyksj/server/SseEmitterServer.java

@@ -0,0 +1,126 @@
+package com.cyksj.server;
+
+
+import lombok.extern.log4j.Log4j2;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+@Log4j2
+public class SseEmitterServer {
+    /**
+     * 当前连接数
+     */
+    private static AtomicInteger count = new AtomicInteger(0);
+
+    /**
+     * 使用map对象,便于根据userId来获取对应的SseEmitter,或者放redis里面
+     */
+    private static Map<Long, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
+
+    /**
+     * 创建用户连接并返回 SseEmitter
+     * @param userId 用户ID
+     * @return SseEmitter
+     */
+    public static SseEmitter connect(Long userId) {
+        SseEmitter sseEmitter = sseEmitterMap.get(userId);
+        if (sseEmitter != null) {
+            return sseEmitter;
+        }
+        // 设置超时时间,0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
+        sseEmitter = new SseEmitter(0L);
+        // 注册回调
+        sseEmitter.onCompletion(completionCallBack(userId));
+        sseEmitter.onError(errorCallBack(userId));
+        sseEmitter.onTimeout(timeoutCallBack(userId));
+        sseEmitterMap.put(userId, sseEmitter);
+        // 数量+1
+        count.getAndIncrement();
+        log.info("创建新的sse连接,当前用户Id:{}", userId);
+        return sseEmitter;
+    }
+
+    /**
+     * 给指定用户发送信息
+     */
+    public static void sendMessage(Long userId, Object message) {
+        if (sseEmitterMap.containsKey(userId)) {
+            try {
+                // sseEmitterMap.get(userId).send(message, MediaType.APPLICATION_JSON);
+                sseEmitterMap.get(userId).send(message);
+            } catch (IOException e) {
+                log.error("用户[{}]推送异常:{}", userId, e.getMessage());
+                removeUser(userId);
+            }
+        }
+    }
+
+
+    /**
+     * 群发所有人
+     */
+    public static void batchSendMessage(String wsInfo) {
+        sseEmitterMap.forEach((k, v) -> {
+            try {
+                v.send(wsInfo, MediaType.APPLICATION_JSON);
+            } catch (IOException e) {
+                log.error("用户[{}]推送异常:{}", k, e.getMessage());
+                removeUser(k);
+            }
+        });
+    }
+
+    /**
+     * 移除用户连接
+     */
+    public static void removeUser(Long userId) {
+        sseEmitterMap.remove(userId);
+        // 数量-1
+        count.getAndDecrement();
+        log.info("移除用户:{}", userId);
+    }
+
+    /**
+     * 获取当前连接信息
+     */
+    public static List<Long> getIds() {
+        return new ArrayList<>(sseEmitterMap.keySet());
+    }
+
+    /**
+     * 获取当前连接数量
+     */
+    public static int getUserCount() {
+        return count.intValue();
+    }
+
+    private static Runnable completionCallBack(Long userId) {
+        return () -> {
+            log.info("结束连接:{}", userId);
+            removeUser(userId);
+        };
+    }
+
+    private static Runnable timeoutCallBack(Long userId) {
+        return () -> {
+            log.info("连接超时:{}", userId);
+            removeUser(userId);
+        };
+    }
+
+    private static Consumer<Throwable> errorCallBack(Long userId) {
+        return throwable -> {
+            log.info("连接异常:{}", userId);
+            removeUser(userId);
+        };
+    }
+
+}

+ 135 - 0
netflix-service/src/main/java/com/cyksj/server/listener/AbstractStreamListener.java

@@ -0,0 +1,135 @@
+package com.cyksj.server.listener;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.cyksj.model.gpt.ChatChoice;
+import com.cyksj.model.gpt.ChatCompletionResponse;
+import com.cyksj.model.gpt.Message;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.Response;
+import okhttp3.sse.EventSource;
+import okhttp3.sse.EventSourceListener;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+
+@Slf4j
+public abstract class AbstractStreamListener extends EventSourceListener {
+
+
+    protected StringBuffer lastMessage = new StringBuffer();
+
+
+    /**
+     * Called when all new message are received.
+     *
+     * @param message the new message
+     */
+    @Setter
+    @Getter
+    protected Consumer<StringBuffer> onComplate = s -> {
+
+    };
+
+    /**
+     * Called when a new message is received.
+     * 收到消息 单个字
+     *
+     * @param message the new message
+     */
+    public abstract void onMsg(Object message) throws IOException;
+
+    /**
+     * Called when an error occurs.
+     * 出错时调用
+     *
+     * @param throwable the throwable that caused the error
+     * @param response  the response associated with the error, if any
+     */
+    public abstract void onError(Throwable throwable, String response);
+
+    @Override
+    public void onOpen(EventSource eventSource, Response response) {
+        // do nothing
+    }
+
+    @Override
+    public void onClosed(EventSource eventSource) {
+        // do nothing
+    }
+
+    @SneakyThrows
+    @Override
+    public void onEvent(EventSource eventSource, String id, String type, String data) {
+        log.info("回答中:{}", data);
+        if (data.equals("[DONE]")) {
+            onComplate.accept(lastMessage);
+            onMsg(Message.ofAssistant("[DONE]"));
+            return;
+        }
+
+        ChatCompletionResponse response = JSONObject.parseObject(data, ChatCompletionResponse.class);
+        // 读取Json
+        List<ChatChoice> choices = response.getChoices();
+        if (choices == null || choices.isEmpty()) {
+            return;
+        }
+        Message delta = choices.get(0).getDelta();
+        String text = delta.getContent();
+        if (text != null) {
+            if(delta.getContent().equals("<!")){
+                delta.setContent("```\\n");
+                text = delta.getContent();
+                lastMessage.append(text);
+                onMsg(delta);
+                delta.setContent("<!");
+                text = delta.getContent();
+                lastMessage.append(text);
+                onMsg(delta);
+            }else {
+                lastMessage.append(text);
+                onMsg(delta);
+            }
+        }
+    }
+
+
+    @SneakyThrows
+    @Override
+    public void onFailure(EventSource eventSource, Throwable throwable, Response response) {
+
+        try {
+            log.error("Stream connection error: {}", throwable);
+
+            String responseText = "";
+
+            if (Objects.nonNull(response)) {
+                responseText = response.body().string();
+            }
+            String[] auth = eventSource.request().headers().toString().split(" ");
+            String key = auth[2];
+            String forbiddenText = "Your access was terminated due to violation of our policies";
+            if (StrUtil.contains(responseText, forbiddenText)) {
+                log.error("Chat session has been terminated due to policy violation");
+                log.error("检测到号被封了");
+            }
+            String overloadedText = "That model is currently overloaded with other requests.";
+            if (StrUtil.contains(responseText, overloadedText)) {
+                log.error("检测到官方超载了,赶紧优化你的代码,做重试吧");
+            }
+            this.onError(throwable, key.replaceAll("\\s*|\r|\n|\t",""));
+        } catch (Exception e) {
+            log.warn("onFailure error:{}", e);
+            // do nothing
+
+        } finally {
+            eventSource.cancel();
+        }
+    }
+}

+ 79 - 0
netflix-service/src/main/java/com/cyksj/server/listener/ConsoleStreamListener.java

@@ -0,0 +1,79 @@
+package com.cyksj.server.listener;
+
+
+import cn.hutool.core.util.StrUtil;
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+import com.cyksj.model.gpt.Message;
+import com.cyksj.server.SendMessageUtil;
+import com.cyksj.service.mini.MiniPopularizeCommonService;
+import lombok.Builder;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+@Slf4j
+@Builder
+public class ConsoleStreamListener extends AbstractStreamListener {
+
+	final Long userId;
+
+	final String conversationId;
+
+	final Long imgRecordId;
+
+	final MiniPopularizeCommonService miniPopularizeCommonService;
+
+	@Override
+	public void onMsg(Object message) {
+		Message delta = (Message) message;
+		String content = delta.getContent();
+		String img = null;
+		if (StrUtil.isNotBlank(content)) {
+			if (content.contains("file")) {
+				String urlPattern = "\\bhttps?://[^\\s/$.?#].[^\\s]*\\b";
+				Pattern pattern = Pattern.compile(urlPattern);
+				Matcher matcher = pattern.matcher(content);
+				while (matcher.find()) {
+					img = matcher.group();
+				}
+				miniPopularizeCommonService.saveImgRecord(setImagRecord(imgRecordId, img, MiniPopularizeUserConversationChat.Status.success, content));
+				//返回图片
+				log.info("返回图片:{}", img);
+				SendMessageUtil.sendMessage(userId, img);
+				return;
+			}
+
+			if (content.contains("失败")) {
+				//将用户使用次数返回
+				miniPopularizeCommonService.recoverUserLimit(userId);
+				miniPopularizeCommonService.saveImgRecord(setImagRecord(imgRecordId, img, MiniPopularizeUserConversationChat.Status.fail, content));
+			}
+		}
+		SendMessageUtil.sendMessage(userId, message);
+	}
+
+	@Override
+	public void onError(Throwable throwable, String response) {
+		//将用户使用次数返回
+		miniPopularizeCommonService.recoverUserLimit(userId);
+		log.error("gpt对话异常,异常key:{}", response);
+		Message message = Message.ofAssistant("图像生成异常");
+		SendMessageUtil.sendMessage(userId, message);
+		message = Message.ofAssistant("[DONE]");
+		SendMessageUtil.sendMessage(userId, message);
+//        asyncService.endOfAnswer(conversationId, "图像生成异常");
+	}
+
+	public MiniPopularizeUserConversationChat setImagRecord(Long imagRecordId, String img, MiniPopularizeUserConversationChat.Status status, String content) {
+		MiniPopularizeUserConversationChat build = MiniPopularizeUserConversationChat.builder()
+				.conversationId(conversationId)
+				.img(img)
+				.type(MiniPopularizeUserConversationChat.Type.image)
+				.content(content)
+				.status(status).build();
+		build.setId(imagRecordId);
+		return build;
+	}
+}

+ 16 - 0
netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeCommonService.java

@@ -0,0 +1,16 @@
+package com.cyksj.service.mini;
+
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeCommonService
+ * 创建者: JavaZou
+ * 创建时间:2025/4/11 11:46
+ */
+public interface MiniPopularizeCommonService {
+
+	void recoverUserLimit(Long id);
+
+	void saveImgRecord(MiniPopularizeUserConversationChat record);
+}

+ 18 - 0
netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeFrontService.java

@@ -0,0 +1,18 @@
+package com.cyksj.service.mini;
+
+import com.cyksj.model.entity.MiniPopularizeUser;
+import com.cyksj.model.request.MiniAiPicturesReq;
+
+import java.io.IOException;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeFrontService
+ * 创建者: JavaZou
+ * 创建时间:2025/4/8 16:51
+ */
+public interface MiniPopularizeFrontService {
+	void createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException;
+
+	MiniPopularizeUser getUser(long userId);
+}

+ 10 - 0
netflix-service/src/main/java/com/cyksj/service/mini/MiniPopularizeService.java

@@ -0,0 +1,10 @@
+package com.cyksj.service.mini;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeService
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:25
+ */
+public interface MiniPopularizeService {
+}

+ 40 - 0
netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeCommonServiceImpl.java

@@ -0,0 +1,40 @@
+package com.cyksj.service.mini.impl;
+
+import com.cyksj.mapper.mini.MiniPopularizeUserConversationChatMapper;
+import com.cyksj.mapper.mini.MiniPopularizeUserMapper;
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.mini.MiniPopularizeCommonService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeCommonServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/4/11 11:46
+ */
+@Service
+@RequiredArgsConstructor
+public class MiniPopularizeCommonServiceImpl implements MiniPopularizeCommonService {
+
+	private final RedisService redisService;
+
+	private final MiniPopularizeUserMapper miniPopularizeUserMapper;
+
+	private final MiniPopularizeUserConversationChatMapper conversationChatMapper;
+
+	@Override
+	public void recoverUserLimit(Long id) {
+		redisService.incr(RedisService.key.MINI_POPULARIZE_GPT_NUM.getName() + id, 1L);
+		miniPopularizeUserMapper.incrNum(id, 1);
+	}
+
+	@Override
+	public void saveImgRecord(MiniPopularizeUserConversationChat record) {
+		Long id = record.getId();
+		if (id != null) {
+			conversationChatMapper.updateById(record);
+		} else conversationChatMapper.insert(record);
+	}
+}

+ 230 - 0
netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeFrontServiceImpl.java

@@ -0,0 +1,230 @@
+package com.cyksj.service.mini.impl;
+
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.http.ContentType;
+import cn.hutool.http.Header;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.mini.*;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.MiniAiPicturesReq;
+import com.cyksj.redis.RedisService;
+import com.cyksj.server.listener.ConsoleStreamListener;
+import com.cyksj.service.mini.MiniPopularizeCommonService;
+import com.cyksj.service.mini.MiniPopularizeFrontService;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.sse.EventSource;
+import okhttp3.sse.EventSources;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeFrontServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/4/8 16:51
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class MiniPopularizeFrontServiceImpl implements MiniPopularizeFrontService {
+	public static final String GPT_URL = "https://api.nf.video/v1/chat/completions";
+
+	public static final String GPT_DRAW_TOKEN = "sk-3x6qkSeXJJoYkaIkhlv7mm0DWGizFc7V7sapmtoMoYI0Nd5Z";
+
+	private final MiniPopularizeUserConversationMapper conversationMapper;
+
+	private final MiniPopularizeUserMapper miniPopularizeUserMapper;
+
+	private final RedisService redisService;
+
+	private final MiniPopularizeCommonService miniPopularizeCommonService;
+
+	private final MiniPopularizeConfigMapper miniPopularizeConfigMapper;
+
+	private final MiniPopularizeUserConversationChatMapper conversationChatMapper;
+	/**
+	 * 连接超时
+	 */
+	private static final long TIMEOUT = 90;
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void createPictures(MiniAiPicturesReq miniAiPicturesReq) throws IOException {
+		String conversationId = miniAiPicturesReq.getConversationId();
+		Long userId = miniAiPicturesReq.getUserId();
+		conversationId = checkUser(MiniPopularizeUserConversation.builder()
+				.userId(userId)
+				.content(miniAiPicturesReq.getTips())
+				.build(), conversationId);
+		miniAiPicturesReq.setConversationId(conversationId);
+		Long configId = miniAiPicturesReq.getId();
+		if (configId != null) {
+			MiniPopularizeConfig miniPopularizeConfig = miniPopularizeConfigMapper.selectById(miniAiPicturesReq.getId());
+			if (miniPopularizeConfig != null) {
+				//垫图
+				if (miniPopularizeConfig.getType() == MiniPopularizeConfig.Type.Stype || miniPopularizeConfig.getType() == MiniPopularizeConfig.Type.Banner) {
+					miniAiPicturesReq.setType(2);
+					miniAiPicturesReq.setImg(miniPopularizeConfig.getImg());
+				}
+				miniAiPicturesReq.setTips(miniPopularizeConfig.getTips());
+			}
+		}
+
+		//聊天记录
+		MiniPopularizeUserConversationChat chat = MiniPopularizeUserConversationChat.builder()
+				.conversationId(conversationId)
+				.content(miniAiPicturesReq.getTips())
+				.type(MiniPopularizeUserConversationChat.Type.text)
+				.userId(userId)
+				.build();
+		conversationChatMapper.insert(chat);
+		//图像生成记录
+		MiniPopularizeUserConversationChat imageRecord = MiniPopularizeUserConversationChat.builder()
+				.userId(miniAiPicturesReq.getUserId())
+				.conversationId(miniAiPicturesReq.getConversationId())
+				.type(MiniPopularizeUserConversationChat.Type.image)
+				.status(MiniPopularizeUserConversationChat.Status.processing)
+				.build();
+
+		miniPopularizeCommonService.saveImgRecord(imageRecord);
+		ConsoleStreamListener listener = ConsoleStreamListener.builder()
+				.userId(userId)
+				.miniPopularizeCommonService(miniPopularizeCommonService)
+				.conversationId(conversationId)
+				.imgRecordId(imageRecord.getId())
+				.build();
+		streamChatCompletion(miniAiPicturesReq, listener);
+	}
+
+	@Override
+	public MiniPopularizeUser getUser(long userId) {
+		MiniPopularizeUser user = miniPopularizeUserMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUser.class)
+				.eq(MiniPopularizeUser::getUserId, userId).last("limit 1").select(MiniPopularizeUser::getNum));
+		return user;
+	}
+
+	private String checkUser(MiniPopularizeUserConversation conversation, String conversationId) {
+		if (conversationId != null) {
+			MiniPopularizeUserConversationChat miniPopularizeUserConversationChat = conversationChatMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class)
+					.eq(MiniPopularizeUserConversationChat::getConversationId, conversationId)
+					.eq(MiniPopularizeUserConversationChat::getType, MiniPopularizeUserConversationChat.Type.image)
+					.orderByDesc(MiniPopularizeUserConversationChat::getId)
+					.last("limit 1"));
+			if (miniPopularizeUserConversationChat == null || !miniPopularizeUserConversationChat.getUserId().equals(conversation.getUserId())) {
+				conversationId = null;
+			} else if (miniPopularizeUserConversationChat.getStatus() != MiniPopularizeUserConversationChat.Status.success) {
+				throw BusinessRuntimeException.getInstance("图片还未生成,无法进行修改");
+			}
+
+			if (conversationId == null) {
+				conversationId = miniPopularizeUserConversationChat.getConversationId();
+				conversation.setConversationId(conversationId);
+			}
+		}
+		Long userId = conversation.getUserId();
+		if (conversationId == null) {
+			//查询当前用户信息
+			MiniPopularizeUser user = miniPopularizeUserMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUser.class).eq(MiniPopularizeUser::getUserId, userId));
+			Long num = 0L;
+			if (user.getNum() == 0) {
+				throw BusinessRuntimeException.getInstance("无可用次数");
+			}
+			num = redisService.decr(RedisService.key.MINI_POPULARIZE_GPT_NUM.getName() + userId, 1L);
+			if (num < 0) {
+				redisService.incr(RedisService.key.MINI_POPULARIZE_GPT_NUM.getName() + userId, 1L);
+			}
+			int i = miniPopularizeUserMapper.decLumaNum(user.getId(), 1, user.getNum());
+			if (i == 0) {
+				redisService.incr(RedisService.key.MINI_POPULARIZE_GPT_NUM.getName() + userId, 1L);
+				throw BusinessRuntimeException.getInstance("网络异常,请稍后再试");
+			}
+			conversation.setConversationId(RandomUtil.randomString(64));
+			conversationMapper.insert(conversation);
+		}
+		return conversationId;
+	}
+
+	/**
+	 * 流式输出
+	 */
+	public void streamChatCompletion(MiniAiPicturesReq miniAiPicturesReq,
+	                                 ConsoleStreamListener eventSourceListener) {
+		JSONObject json = new JSONObject();
+		json.putOpt("model", "gpt-4o-image-vip");
+		json.putOpt("stream", true);
+		JSONArray messages = new JSONArray();
+		String conversationId = miniAiPicturesReq.getConversationId();
+		MiniPopularizeUserConversationChat miniPopularizeUserConversationChat = null;
+		if (conversationId != null) {
+			miniPopularizeUserConversationChat = conversationChatMapper.selectOne(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class)
+					.eq(MiniPopularizeUserConversationChat::getConversationId, conversationId)
+					.eq(MiniPopularizeUserConversationChat::getStatus, MiniPopularizeUserConversationChat.Status.success)
+					.last("limit 1"));
+		}
+		//原图上修改
+		if (miniPopularizeUserConversationChat != null && miniPopularizeUserConversationChat.getStatus() != null && miniPopularizeUserConversationChat.getStatus() == MiniPopularizeUserConversationChat.Status.success) {
+			//组装上下文
+			contentMsg(messages, miniPopularizeUserConversationChat.getConversationId());
+		} else {
+			if (miniAiPicturesReq.getType() == 2) {
+				String img = miniAiPicturesReq.getImg();
+				messages.add(JSONUtil.createObj().set("role", "user").set("content", JSONUtil.createArray().set(JSONUtil.createObj().set("type", "text").set("text", miniAiPicturesReq.getTips()))
+						.set(JSONUtil.createObj().set("type", "image_url").set("image_url", JSONUtil.createObj().set("url", img)))));
+			} else {
+				messages.add(JSONUtil.createObj().set("role", "user").set("content", miniAiPicturesReq.getTips()));
+			}
+		}
+		json.putOpt("messages", messages);
+		try {
+			EventSource.Factory factory = EventSources.createFactory(getOkHttpClient());
+			ObjectMapper mapper = new ObjectMapper();
+			String requestBody = mapper.writeValueAsString(json);
+			Request request = new Request.Builder()
+					.url(GPT_URL)
+					.post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()),
+							requestBody))
+					.header(Header.AUTHORIZATION.name(), GPT_DRAW_TOKEN)
+					.build();
+			factory.newEventSource(request, eventSourceListener);
+		} catch (Exception e) {
+			log.error("gpt create image请求出错:{}", StringUtil.getErrorText(e));
+		}
+	}
+
+	private void contentMsg(JSONArray messages, String conversationId) {
+		List<MiniPopularizeUserConversationChat> miniPopularizeUserConversationChats = conversationChatMapper.selectList(Wrappers.lambdaQuery(MiniPopularizeUserConversationChat.class)
+				.eq(MiniPopularizeUserConversationChat::getConversationId, conversationId));
+		miniPopularizeUserConversationChats.forEach(chat->{
+			if (chat.getStatus() != null && chat.getStatus() == MiniPopularizeUserConversationChat.Status.processing) {
+				return;
+			}
+			String content = chat.getContent();
+			if (chat.getType() == MiniPopularizeUserConversationChat.Type.text) {
+				messages.add(JSONUtil.createObj().set("role", "user").set("content", content));
+			} else messages.add(JSONUtil.createObj().set("role", "assistant").set("content", content));
+		});
+	}
+
+	public OkHttpClient getOkHttpClient() {
+		OkHttpClient.Builder client = new OkHttpClient.Builder();
+		client.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
+		client.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
+		client.readTimeout(TIMEOUT, TimeUnit.SECONDS);
+		return client.build();
+	}
+}

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniPopularizeServiceImpl.java

@@ -0,0 +1,14 @@
+package com.cyksj.service.mini.impl;
+
+import com.cyksj.service.mini.MiniPopularizeService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:25
+ */
+@Service
+public class MiniPopularizeServiceImpl implements MiniPopularizeService {
+}

+ 22 - 1
netflix-service/src/main/java/com/cyksj/service/mini/impl/MiniServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.util.Times;
+import com.cyksj.config.TgMiniConfig;
 import com.cyksj.config.YhCertMiniConfig;
 import com.cyksj.config.YhMiniConfig;
 import com.cyksj.dto.Result;
@@ -12,9 +13,11 @@ import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.mini.ArticleMapper;
 import com.cyksj.mapper.mini.ArticleUserMarkMapper;
+import com.cyksj.mapper.mini.MiniPopularizeUserMapper;
 import com.cyksj.model.dto.MiniProgramSession;
 import com.cyksj.model.entity.Article;
 import com.cyksj.model.entity.ArticleUserMark;
+import com.cyksj.model.entity.MiniPopularizeUser;
 import com.cyksj.model.entity.User;
 import com.cyksj.model.request.MiniArticleReq;
 import com.cyksj.model.request.MiniSchemaReq;
@@ -56,6 +59,10 @@ public class MiniServiceImpl implements MiniService {
 
 	private final RedisService redisService;
 
+	private final MiniPopularizeUserMapper miniPopularizeUserMapper;
+
+	private final TgMiniConfig tgMiniConfig;
+
 	@Override
 	public String getMiniURLLink(String path, String query) throws Exception {
 		MiniURLLink miniURLLink = new MiniURLLink();
@@ -84,7 +91,8 @@ public class MiniServiceImpl implements MiniService {
 		if (user.getId() == null) {
 			user.setNickname(String.format("银河小程序用户%s", RandomUtil.randomString(5)));
 			userMapper.insert(user);
-
+			//推广小程序用户 新注册发送GPT画图使用额度
+			sendGptMirrorImageNumIfPopularizeMini(user.getId(), appId);
 		} else {
 			userMapper.updateById(user);
 		}
@@ -213,4 +221,17 @@ public class MiniServiceImpl implements MiniService {
 			}
 		}
 	}
+
+	private void sendGptMirrorImageNumIfPopularizeMini(Long userId, String appId) {
+		if (StrUtil.equals(tgMiniConfig.getAppId(), appId)) {
+			MiniPopularizeUser user = new MiniPopularizeUser();
+			user.setUserId(userId);
+			user.setNum(5);
+			try {
+				miniPopularizeUserMapper.insert(user);
+			} catch (DuplicateKeyException e) {
+
+			}
+		}
+	}
 }

+ 5 - 0
netflix-web/pom.xml

@@ -60,6 +60,11 @@
             <artifactId>sa-token-spring-boot-starter</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp-sse</artifactId>
+        </dependency>
+
 
 
     </dependencies>

+ 163 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/mini/MiniPopularizeController.java

@@ -0,0 +1,163 @@
+package com.cyksj.web.controller.manage.mini;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.mini.MiniPopularizeConfigCategoryMapper;
+import com.cyksj.mapper.mini.MiniPopularizeConfigMapper;
+import com.cyksj.model.entity.MiniPopularizeConfig;
+import com.cyksj.model.entity.MiniPopularizeConfigCategory;
+import com.cyksj.model.request.MiniPopularizeCategoryUpdateReq;
+import com.cyksj.model.request.MiniPopularizeConfigReq;
+import com.cyksj.model.views.MiniPopularizeConfigView;
+import com.cyksj.service.mini.MiniPopularizeService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.dao.DataAccessException;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: MiniPopularizeController
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:12
+ */
+@RestController
+@RequestMapping("/manage/mini/popularize")
+@RequiredArgsConstructor
+public class MiniPopularizeController {
+	private final MiniPopularizeService miniPopularizeService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	private final MiniPopularizeConfigMapper miniPopularizeConfigMapper;
+
+	private final MiniPopularizeConfigCategoryMapper miniPopularizeConfigCategoryMapper;
+
+	/**
+	 * 配置列表
+	 */
+	@GetMapping("/get/config")
+	public Result<SearchResult<MiniPopularizeConfigView>> getConfig() {
+		SearchResult<MiniPopularizeConfigView> search = beanSearcher.search(MiniPopularizeConfigView.class, MapUtils.flatBuilder(request.getParameterMap()).orderBy(MiniPopularizeConfigView::getUpdateTime).desc().build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+
+	/**
+	 * 新增配置
+	 */
+	@PostMapping("/save")
+	public Result<String> save(@RequestBody MiniPopularizeConfig miniPopularizeConfig) {
+		miniPopularizeConfigMapper.insert(miniPopularizeConfig);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 编辑配置
+	 */
+	@PostMapping("/update")
+	public Result<String> update(@RequestBody MiniPopularizeConfig miniPopularizeConfig) {
+		miniPopularizeConfigMapper.updateById(miniPopularizeConfig);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 删除配置
+	 */
+	@DeleteMapping("/delete/{id}")
+	public Result<String> deleteById(@PathVariable Long id) {
+		miniPopularizeConfigMapper.deleteById(id);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 上下架配置
+	 */
+	@PutMapping("/update/status")
+	public Result<String> updateStatusById(@PathVariable Long id) {
+		Optional.ofNullable(miniPopularizeConfigMapper.selectById(id)).ifPresent(data -> {
+			data.setStatus(!data.getStatus());
+			miniPopularizeConfigMapper.updateById(data);
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 批量上下架
+	 */
+	@PutMapping("/batch/update/status")
+	public Result<String> updateStatusByIds(@RequestBody MiniPopularizeConfigReq req) {
+		miniPopularizeConfigMapper.update(null, Wrappers.lambdaUpdate(MiniPopularizeConfig.class)
+				.set(MiniPopularizeConfig::getStatus, req.getStatus())
+				.in(MiniPopularizeConfig::getId, req.getIds())
+				.ne(MiniPopularizeConfig::getStatus, req.getStatus()));
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+
+	//==============================================================分类==========================================================================================
+
+	/**
+	 * 新增分类
+	 */
+	@PostMapping("/category/save")
+	public Result<String> saveCategory(@RequestBody MiniPopularizeConfigCategory configCategory) {
+		try {
+			miniPopularizeConfigCategoryMapper.insert(configCategory);
+			configCategory.setSorted(configCategory.getId().intValue());
+			miniPopularizeConfigCategoryMapper.updateById(configCategory);
+		} catch (DataAccessException e) {
+			throw BusinessRuntimeException.getInstance("重复分类");
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 编辑分类
+	 */
+	@PutMapping("/category/save")
+	public Result<String> saveCategory(@RequestBody MiniPopularizeCategoryUpdateReq req) {
+		for (MiniPopularizeConfigCategory configCategory : req.getCategories()) {
+			if (configCategory.getId() == null) {
+				try {
+					miniPopularizeConfigCategoryMapper.insert(configCategory);
+					configCategory.setSorted(configCategory.getId().intValue());
+					miniPopularizeConfigCategoryMapper.updateById(configCategory);
+				} catch (DataAccessException e) {
+
+				}
+			} else miniPopularizeConfigCategoryMapper.updateById(configCategory);
+		}
+		List<Long> delIds = req.getDelIds();
+		if (CollUtil.isNotEmpty(delIds)) {
+			Set<Long> existsIds = miniPopularizeConfigMapper.selectList(Wrappers.lambdaQuery(MiniPopularizeConfig.class).in(MiniPopularizeConfig::getCid, delIds)).stream().map(MiniPopularizeConfig::getCid).collect(Collectors.toSet());
+			if (CollUtil.isNotEmpty(existsIds)) {
+				delIds.remove(existsIds);
+			}
+			miniPopularizeConfigCategoryMapper.deleteBatchIds(delIds);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 分类列表
+	 */
+	@GetMapping("/category/get")
+	public Result<List<MiniPopularizeConfigCategory>> getCategory() {
+		List<MiniPopularizeConfigCategory> miniPopularizeConfigCategories = beanSearcher.searchAll(MiniPopularizeConfigCategory.class, MapUtils.flatBuilder(request.getParameterMap()).orderBy(MiniPopularizeConfigCategory::getSorted).asc().build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(miniPopularizeConfigCategories);
+	}
+}

+ 91 - 0
netflix-web/src/main/java/com/cyksj/web/controller/mini/PopularizeMiniController.java

@@ -0,0 +1,91 @@
+package com.cyksj.web.controller.mini;
+
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.MiniPopularizeUser;
+import com.cyksj.model.entity.MiniPopularizeUserConversationChat;
+import com.cyksj.model.request.MiniAiPicturesReq;
+import com.cyksj.model.views.MiniPopularizeConfigFrontView;
+import com.cyksj.model.views.MiniPopularizeUserConversationImgRecordsView;
+import com.cyksj.service.mini.MiniPopularizeFrontService;
+import com.cyksj.web.util.StpUserUtil;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: PopularizeMiniController
+ * 创建者: JavaZou
+ * 创建时间:2025/4/7 16:01
+ */
+@RestController
+@RequestMapping("/applets/mini/popularize")
+@RequiredArgsConstructor
+@Slf4j
+public class PopularizeMiniController {
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	private final MiniPopularizeFrontService miniPopularizeFrontService;
+
+	/**
+	 * 推广小程序 配置
+	 */
+	@GetMapping("/get/config")
+	public Result<List<MiniPopularizeConfigFrontView>> getConfig() {
+		List<MiniPopularizeConfigFrontView> miniPopularizeConfigFrontViews = beanSearcher.searchAll(MiniPopularizeConfigFrontView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(miniPopularizeConfigFrontViews);
+	}
+
+	/**
+	 * 创作 图片
+	 */
+	@PostMapping("/create/pictures")
+	public void createPictures(@RequestBody MiniAiPicturesReq miniAiPicturesReq) throws IOException {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		miniAiPicturesReq.setUserId(userId);
+		miniPopularizeFrontService.createPictures(miniAiPicturesReq);
+	}
+
+	/**
+	 * 创作记录
+	 */
+	@GetMapping("/get/chat")
+	public Result<SearchResult<MiniPopularizeUserConversationImgRecordsView>> getChat() throws IOException {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		SearchResult<MiniPopularizeUserConversationImgRecordsView> search = beanSearcher.search(MiniPopularizeUserConversationImgRecordsView.class, MapUtils.builder().field(MiniPopularizeUserConversationImgRecordsView::getUserId, userId).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 个人作品
+	 */
+	@GetMapping("/get/personal")
+	public Result<SearchResult<MiniPopularizeUserConversationChat>> getPersonal() throws IOException {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		SearchResult<MiniPopularizeUserConversationChat> search = beanSearcher.search(MiniPopularizeUserConversationChat.class, MapUtils.builder()
+				.field(MiniPopularizeUserConversationChat::getUserId, userId)
+				.field(MiniPopularizeUserConversationChat::getType, MiniPopularizeUserConversationChat.Type.image.name())
+				.orderBy(MiniPopularizeUserConversationChat::getId).desc().build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 个人次数
+	 */
+	@GetMapping("/get/user")
+	public Result<MiniPopularizeUser> getUser() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		MiniPopularizeUser user = miniPopularizeFrontService.getUser(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(user);
+	}
+}

+ 37 - 0
netflix-web/src/main/java/com/cyksj/web/controller/sse/SseController.java

@@ -0,0 +1,37 @@
+package com.cyksj.web.controller.sse;
+
+
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.server.SseEmitterServer;
+import com.cyksj.web.util.StpUserUtil;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+@RestController
+@RequestMapping("/sse")
+@Log4j2
+public class SseController {
+
+    /**
+     * 用于创建连接
+     */
+    @GetMapping("/connect")
+    public SseEmitter connect() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        return SseEmitterServer.connect(userId);
+    }
+
+    /**
+     * 关闭连接
+     */
+    @GetMapping("/close")
+    public Result<String> close() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        SseEmitterServer.removeUser(userId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult("连接关闭");
+    }
+}

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
netflix-web/src/main/resources/application-dev.yml


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
netflix-web/src/main/resources/application-prd.yml


+ 6 - 1
netflix-web/src/main/resources/application-pre.yml

@@ -144,7 +144,7 @@ wx-login:
   yhShopRedirectUri: https://nf.video/8082/api/yhShop/manage/wx/authLogin/baseRedirect
   yhShopLoginUrl: https://shop.liuliangbang.vip/mall/admin/loginNexte
   baRedirectUrl: https://nf.video/8082/api/applets/market/task/bind/wx/baseRedirect
-  cpsWebRedirectUri: https://inside.liuliangbang.vip/yinhe/cps/homePage
+  cpsWebRedirectUri: https://cps.nf.video/test/cps/homePage
   userMirrorShopRedirectUri: https://bestaistore.com/8082/api/mirrorShop/manage/wx/authLogin/baseRedirect
   userMirrorShopLoginUrl: https://bestaistore.com/mirrorTest/web/
   remark: 银河录像网页微信登录
@@ -173,6 +173,11 @@ certmini:
   appid: wx16e441d61fa3fd8a
   secret: edc2e8ed29a45d6ba266a63bc7ffc2b5
 
+#银河推广小程序
+tgmini:
+  appid: wx383c483d3bcf155a
+  secret: bf6ca029a3102f390486a7a14b218b06
+
 #广告投放小程序
 advertisement:
   appId: wx895f960ea6b8c5d0

+ 5 - 0
pom.xml

@@ -135,6 +135,11 @@
             <artifactId>bean-searcher-boot-starter</artifactId>
             <version>3.8.0</version>
         </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp-sse</artifactId>
+            <version>3.14.9</version>
+        </dependency>
 
 <!--        <dependency>-->
 <!--            <groupId>org.apache.httpcomponents</groupId>-->

Неке датотеке нису приказане због велике количине промена