update youtube dashboard

master
嘉祥 詹 2024-05-03 17:19:05 +08:00
parent 66902d1200
commit bcf793cd92
11 changed files with 541 additions and 5 deletions

View File

@ -59,6 +59,33 @@ namespace Journeys_WantHome.Controllers
this._httpContextAccessor = httpContextAccessor; this._httpContextAccessor = httpContextAccessor;
} }
[Route("youtubeList")]
public ActionResult YoutubeList(IFormCollection obj) {
youtubeListResult ret = new youtubeListResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
List<youtube> youtubes = conn.Query<youtube>("select top 15 * from youtube where youtube_revoke = 'N' order by youtube_subscriberCount desc").ToList();
foreach (youtube objItem in youtubes) {
youtubeDetailClass detail = new youtubeDetailClass(objItem);
ret.youtubeList.Add(detail);
}
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("projectKolViewList")] [Route("projectKolViewList")]
public ActionResult ProjectKolViewList(IFormCollection obj) { public ActionResult ProjectKolViewList(IFormCollection obj) {
projectKolViewResult ret = new projectKolViewResult(); projectKolViewResult ret = new projectKolViewResult();
@ -1900,6 +1927,15 @@ namespace Journeys_WantHome.Controllers
} }
public class youtubeListResult
{
public string ret { get; set; } = "no";
public string err_code { get; set; } = "0000";
public string message { get; set; } = "";
public List<youtubeDetailClass> youtubeList = new List<youtubeDetailClass>();
}
public class projectKolViewResult public class projectKolViewResult
{ {
public string ret { get; set; } = "no"; public string ret { get; set; } = "no";

View File

@ -8,6 +8,74 @@ using Newtonsoft.Json.Linq;
public class DbTableClass public class DbTableClass
{ {
[Table("youtubeDetail")]
public class youtubeDetail
{
[JsonIgnore]
[Key]
public int youtubeDetail_sn { get; set; }
public string youtube_uid { get; set; } = "";
public string youtubeDetail_uid { get; set; } = "";
public DateTime? youtubeDetail_publishedAt { get; set; }
public string youtubeDetail_title { get; set; } = "";
public string youtubeDetail_description { get; set; } = "";
public string youtubeDetail_thumbnails { get; set; } = "";
public string youtubeDetail_videoId { get; set; } = "";
public int youtubeDetail_viewCount { get; set; } = 0;
public int youtubeDetail_likeCount { get; set; } = 0;
public int youtubeDetail_favoriteCount { get; set; } = 0;
public int youtubeDetail_commentCount { get; set; } = 0;
[JsonIgnore]
public string youtubeDetail_json { get; set; } = "";
public DateTime youtubeDetail_createdate { get; set; } = DateTime.Now;
}
[Table("youtube")]
public class youtube
{
[JsonIgnore]
[Key]
public int youtube_sn { get; set; }
public string youtube_uid { get; set; } = "";
public string kol_uid { get; set; } = "";
public string kolMedia_uid { get; set; } = "";
public string youtube_name { get; set; } = "";
public string youtube_account { get; set; } = "";
public string youtube_revoke { get; set; } = "N";
public int youtube_subscriberCount { get; set; } = 0;
public int youtube_viewCount { get; set; } = 0;
public int youtube_avgViewCount { get; set; } = 0;
public string youtube_photo { get; set; } = "";
[JsonIgnore]
public string youtube_json { get; set; } = "";
public DateTime youtube_updateTime { get; set; } = DateTime.Now;
}
[Table("updateLog")]
public class updateLog
{
[JsonIgnore]
[Key]
public int updateLog_sn { get; set; }
public string updateLog_type { get; set; } = "";
public string updateLog_kol_uid { get; set; } = "";
public string updateLog_kolMedia_uid { get; set; } = "";
public string updateLog_kolMedia_accountName { get; set; } = "";
public string updateLog_kolMedia_displayName { get; set; } = "";
public string updateLog_result { get; set; } = "faild";
public string updateLog_uid { get; set; } = "";
[JsonIgnore]
public string updateLog_text { get; set; } = "";
public DateTime updateLog_updateTime { get; set; } = DateTime.Now;
}
[Table("kolProjectView")] [Table("kolProjectView")]
public class kolProjectView public class kolProjectView
{ {

View File

@ -0,0 +1,63 @@
using Dapper;
using Dapper.Contrib.Extensions;
using NPOI.SS.Formula.Functions;
using System.Data.SqlClient;
using System.Security.Cryptography.X509Certificates;
using static DbTableClass;
public class youtubeDetailClass : youtube
{
DbConn dbConn = new DbConn();
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
List<youtubeDetail> youtubeDetails = new List<youtubeDetail>();
private youtube _youtube;
public youtubeDetailClass()
{
_youtube = new youtube();
}
public youtubeDetailClass(youtube youtubeObj)
{
Type youtubeType = youtubeObj.GetType();
foreach (var prop in youtubeType.GetProperties())
{
string propName = prop.Name;
var valueProperty = youtubeType.GetProperty(propName);
object propValue = valueProperty.GetValue(youtubeObj, null);
this.GetType().GetProperty(propName).SetValue(this, propValue);
}
_youtube = youtubeObj;
loadList();
}
public youtubeDetailClass(string youtube_uid) {
_youtube = conn.QueryFirstOrDefault<youtube>("select * from youtube where youtube_uid = @youtube_uid", new { youtube_uid = youtube_uid });
if (_youtube != null)
{
youtube youtubeObj = _youtube;
Type youtubeType = youtubeObj.GetType();
foreach (var prop in youtubeType.GetProperties())
{
string propName = prop.Name;
var valueProperty = youtubeType.GetProperty(propName);
object propValue = valueProperty.GetValue(youtubeObj, null);
this.GetType().GetProperty(propName).SetValue(this, propValue);
}
loadList();
}
}
private void loadList()
{
youtubeDetails = conn.Query<youtubeDetail>("select * from youtubeDetail where youtube_uid = @youtube_uid", new { youtube_uid = _youtube.youtube_uid }).ToList();
}
}

View File

@ -0,0 +1,235 @@
using Dapper;
using Dapper.Contrib.Extensions;
using Newtonsoft.Json;
using NPOI.XSSF.UserModel;
using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using System.Web;
using static DbTableClass;
using Org.BouncyCastle.Crypto.Operators;
using System.Globalization;
public class youtubeUpdateClass : IHostedService, IDisposable
{
static Timer _timer;
private int execCount = 0;
DbConn dbConn = new DbConn();
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
public youtubeUpdateClass() { }
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null,
TimeSpan.Zero,
TimeSpan.FromSeconds(5 * 60));
return Task.CompletedTask;
}
public async void DoWork(object state) {
conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork')");
//利用 Interlocked 計數防止重複執行
Interlocked.Increment(ref execCount);
if (execCount == 1) {
conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWorkexecCount == 1時執行更新工作')");
//撈出Youtube頻道清單
List<kolMedia> kolMedias = conn.Query<kolMedia>("select * from kolMedia where option_uid = 'media' and optionItem_uid = 'media003' ").ToList();
foreach(kolMedia mediaItem in kolMedias)
{
string overDate = DateTime.Now.AddDays(int.Parse(GlobalClass.appsettings("UpdateByDay")) * -1).ToString("yyyy/MM/dd HH:mm:ss");
updateLog objLog = conn.QueryFirstOrDefault<updateLog>("select * from updateLog where updateLog_type = 'YouTube' and updateLog_result = 'success' and updateLog_kol_uid = @kol_uid and updateLog_kolMedia_uid = @kolMedia_uid and updateLog_updateTime >= @overDate ", new { kol_uid = mediaItem.kol_uid, kolMedia_uid = mediaItem.kolMedia_uid, overDate = overDate });
if (objLog == null) {
//撈取youtube帳號訂閱數
string youtubeChannelsApi = "https://www.googleapis.com/youtube/v3/channels?part=statistics,snippet,contentDetails&forHandle=" + mediaItem.kolMedia_accountName + "&key=" + GlobalClass.appsettings("GoogleKey");
string channelsStatus = "";
string channel_id = "";
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync(youtubeChannelsApi))
{
channelsStatus = await response.Content.ReadAsStringAsync();
}
}
dynamic channelsObj;
channelsObj = JsonConvert.DeserializeObject(channelsStatus);
if (channelsObj.items != null)
{
channel_id = channelsObj.items[0].id;
string subscriberCount = channelsObj.items[0].statistics.subscriberCount;
mediaItem.kolMedia_fansNum = (int)channelsObj.items[0].statistics.subscriberCount;
string youtube_uid = GlobalClass.CreateRandomCode(32);
youtube newYoutube = new youtube();
newYoutube.youtube_uid = youtube_uid;
newYoutube.kol_uid = mediaItem.kol_uid;
newYoutube.kolMedia_uid = mediaItem.kolMedia_uid;
newYoutube.youtube_account = mediaItem.kolMedia_accountName;
newYoutube.youtube_name = channelsObj.items[0].snippet.title;
newYoutube.youtube_photo = channelsObj.items[0].snippet.thumbnails.high.url;
newYoutube.youtube_revoke = "N";
newYoutube.youtube_subscriberCount = (int)channelsObj.items[0].statistics.subscriberCount;
newYoutube.youtube_viewCount = (int)channelsObj.items[0].statistics.viewCount;
newYoutube.youtube_json = channelsStatus;
//取得上傳影片的playlist id
string playlist_id = channelsObj.items[0].contentDetails.relatedPlaylists.uploads;
string youtubePlaylistApi = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=5&key=" + GlobalClass.appsettings("GoogleKey") + "&playlistId=" + playlist_id;
string youtubePlaylistJson = "";
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync(youtubePlaylistApi))
{
youtubePlaylistJson = await response.Content.ReadAsStringAsync();
}
}
dynamic youtubePlaylistObj;
youtubePlaylistObj = JsonConvert.DeserializeObject(youtubePlaylistJson);
string videoIdList = "";
foreach (var item in youtubePlaylistObj.items) {
videoIdList += item.snippet.resourceId.videoId + ",";
}
videoIdList = videoIdList.TrimEnd(',');
if (videoIdList == "")
{
updateLog failedLog = new updateLog();
failedLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Google Youtube Data Api 的Video數量 回傳0個!";
failedLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid;
failedLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName;
failedLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName;
failedLog.updateLog_kol_uid = mediaItem.kol_uid;
failedLog.updateLog_type = "YouTube";
failedLog.updateLog_result = "failed";
conn.Insert(failedLog);
}
else
{
string youtubeVideoApi = "https://www.googleapis.com/youtube/v3/videos?part=statistics,snippet&key=" + GlobalClass.appsettings("GoogleKey") + "&id=" + videoIdList;
string youtubeVideoJson = "";
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync(youtubeVideoApi))
{
youtubeVideoJson = await response.Content.ReadAsStringAsync();
}
}
dynamic youtubeVideoObj;
youtubeVideoObj = JsonConvert.DeserializeObject(youtubeVideoJson);
int totalViewNum = 0;
int videosNum = 0;
List<youtubeDetail> youtubeDetailList = new List<youtubeDetail>();
foreach (var item in youtubeVideoObj.items) {
totalViewNum += (int)item.statistics.viewCount;
videosNum++;
youtubeDetail objDetail = new youtubeDetail();
objDetail.youtube_uid = youtube_uid;
objDetail.youtubeDetail_uid = "ytd_" + GlobalClass.CreateRandomCode(16);
objDetail.youtubeDetail_title = item.snippet.title;
objDetail.youtubeDetail_description = item.snippet.description;
string publishedAt = item.snippet.publishedAt;
var published = DateTime.Parse(publishedAt, null, DateTimeStyles.None);
objDetail.youtubeDetail_publishedAt = published;
objDetail.youtubeDetail_commentCount = (int)item.statistics.commentCount;
objDetail.youtubeDetail_viewCount = (int)item.statistics.viewCount;
objDetail.youtubeDetail_likeCount = (int)item.statistics.likeCount;
objDetail.youtubeDetail_favoriteCount = (int)item.statistics.favoriteCount;
objDetail.youtubeDetail_thumbnails = item.snippet.thumbnails.maxres.url;
objDetail.youtubeDetail_videoId = item.id;
objDetail.youtubeDetail_json = JsonConvert.SerializeObject(item);
youtubeDetailList.Add(objDetail);
}
double avg = ((totalViewNum / videosNum) + 0.5);
newYoutube.youtube_avgViewCount = (int)System.Math.Floor(avg);
conn.Execute("update youtube set youtube_revoke = 'Y' where kol_uid = @kol_uid and kolMedia_uid = @kolMedia_uid", new { kol_uid = mediaItem.kol_uid, kolMedia_uid = mediaItem.kolMedia_uid });
conn.Insert(youtubeDetailList);
conn.Insert(newYoutube);
}
updateLog successLog = new updateLog();
successLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Youtube資料更新成功";
successLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid;
successLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName;
successLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName;
successLog.updateLog_kol_uid = mediaItem.kol_uid;
successLog.updateLog_type = "YouTube";
successLog.updateLog_result = "success";
successLog.updateLog_uid = channel_id;
conn.Insert(successLog);
}
else {
updateLog failedLog = new updateLog();
failedLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Google Youtube Data Api回傳Null值!";
failedLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid;
failedLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName;
failedLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName;
failedLog.updateLog_kol_uid = mediaItem.kol_uid;
failedLog.updateLog_type = "YouTube";
failedLog.updateLog_result = "failed";
conn.Insert(failedLog);
}
}
}
conn.Update(kolMedias);
conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork執行更新工作結束')");
}
Interlocked.Decrement(ref execCount);
conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWorkexecCount減1')");
}
public Task StopAsync(CancellationToken cancellationToken)
{
//調整Timer為永不觸發停用定期排程
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}

View File

@ -5,6 +5,7 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddControllersWithViews(); builder.Services.AddControllersWithViews();
builder.Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); builder.Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddHostedService<youtubeUpdateClass>();
var app = builder.Build(); var app = builder.Build();

View File

@ -6,10 +6,12 @@
} }
@section Style { @section Style {
<link rel="stylesheet" href="~/assets/vendor/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css">
} }
@section Script { @section Script {
<script src="~/assets/vendor/sortablejs/Sortable.min.js"></script>
<script src="~/assets/vendor/nestable2/jquery.nestable.min.js"></script>
<script src="~/assets/javascript/custom/dashboard.js" asp-append-version="true"></script> <script src="~/assets/javascript/custom/dashboard.js" asp-append-version="true"></script>
<script> <script>
const numberInput = document.getElementById('myNumberInput'); const numberInput = document.getElementById('myNumberInput');
@ -21,3 +23,28 @@
</script> </script>
} }
<!-- .page-inner -->
<div class="page-inner">
<!-- .page-title-bar -->
<header class="page-title-bar">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active">
<a href="#"><i class="breadcrumb-icon fa fa-angle-left mr-2"></i>Dashboard</a>
</li>
</ol>
</nav>
<h1 class="page-title"> 社群平台排行榜 </h1>
</header><!-- /.page-title-bar -->
<!-- .page-section -->
<div class="page-section">
<!-- .section-block -->
<div class="section-block" style="display: none;">
<h2 class="section-title"> Nestable </h2>
<p class="text-muted"> Drag & drop hierarchical list with mouse and touch compatibility. </p>
</div><!-- /.section-block -->
<!-- grid row -->
<div class="row" id="card_group">
</div><!-- /grid row -->
</div><!-- /.page-section -->
</div><!-- /.page-inner -->

View File

@ -23,6 +23,7 @@
<!-- GOOGLE FONT --> <!-- GOOGLE FONT -->
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:400,500,600" rel="stylesheet"><!-- End GOOGLE FONT --> <link href="https://fonts.googleapis.com/css?family=Fira+Sans:400,500,600" rel="stylesheet"><!-- End GOOGLE FONT -->
<!-- BEGIN PLUGINS STYLES --> <!-- BEGIN PLUGINS STYLES -->
<link rel="stylesheet" href="~/assets/vendor/open-iconic/font/css/open-iconic-bootstrap.min.css"> <link rel="stylesheet" href="~/assets/vendor/open-iconic/font/css/open-iconic-bootstrap.min.css">
<link rel="stylesheet" href="~/assets/vendor/fortawesome/fontawesome-free/css/all.min.css"> <link rel="stylesheet" href="~/assets/vendor/fortawesome/fontawesome-free/css/all.min.css">
<link rel="stylesheet" href="~/assets/vendor/select2/css/select2.min.css"> <link rel="stylesheet" href="~/assets/vendor/select2/css/select2.min.css">

View File

@ -7,7 +7,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"SQLConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=journeys_wanthome;User ID=journeys_wanthome;Password=2icR52n@9;Max Pool Size=250;", "SQLConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=journeys_wanthome;User ID=journeys_wanthome;Password=2icR52n@9;Max Pool Size=500;",
"ElabConnectionString": "Data Source=sql.bremen.com.tw;database=elab;uid=elab;pwd=2#2k9Vfg", "ElabConnectionString": "Data Source=sql.bremen.com.tw;database=elab;uid=elab;pwd=2#2k9Vfg",
"DBConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=prm;User ID=prm;Password=y6U6x?t5;Max Pool Size=250;" "DBConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=prm;User ID=prm;Password=y6U6x?t5;Max Pool Size=250;"
}, },
@ -16,5 +16,7 @@
"id": "admin", "id": "admin",
"pwd": "?Bremen!", "pwd": "?Bremen!",
"perm": "system" "perm": "system"
} },
"GoogleKey": "AIzaSyBGUAe21kB_qRq2XmenGgWu_gUvDYL39PE",
"UpdateByDay": "1"
} }

View File

@ -1,5 +1,101 @@
 
$(document).ready(function () { $(document).ready(function () {
loadYoutubeCard();
});
}); function loadYoutubeCard() {
$.ajax({
url: "/Api/youtubeList",
type: "post",
data: null,
success: function (data, textStatus, jqXHR) {
if (data.ret == "yes") {
var obj = data.youtubeList;
$('#card_group').append(youtubeCardHtml(obj));
} else {
alert(data.message);
if (data.err_code == "99999") {
location.href = "/Root/Login";
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('網路或伺服器發生錯誤,請稍後重試!');
}
});
}
function youtubeCardHtml(objItem) {
var html = "";
html += "<!-- grid column -->";
html += "<div class=\"col-xl-6\">";
html += " <!-- .card -->";
html += " <div class=\"card card-fluid\">";
html += " <!-- .card-header -->";
html += " <div class=\"card-header border-0\">";
html += " <!-- .d-flex -->";
html += " <div class=\"d-flex align-items-center\">";
html += " <span class=\"mr-auto\">Youtube 頻道排行</span> <!-- .card-header-control -->";
html += " <div class=\"card-header-control\">";
html += " </div><!-- /.card-header-control -->";
html += " </div><!-- /.d-flex -->";
html += " </div><!-- /.card-header -->";
html += " <!-- .table-responsive -->";
html += " <div class=\"table-responsive\">";
html += " <!-- .table -->";
html += " <table class=\"table\">";
html += " <!-- thead -->";
html += " <thead>";
html += " <tr>";
html += " <th style=\"min-width:259px\"> 頻道名稱 </th>";
html += " <th> 帳號 </th>";
html += " <th class=\"text-right\"> 訂閱數 </th>";
html += " <th class=\"text-right\"> 平均觀看數(近5) </th>";
html += " <th> </th>";
html += " </tr>";
html += " </thead><!-- /thead -->";
html += " <!-- tbody -->";
html += " <tbody>";
html += " <!-- tr -->";
$.each(objItem, function (index, item) {
html += youtubeSubHtml(item);
});
html += " </tbody><!-- /tbody -->";
html += " </table><!-- /.table -->";
html += " </div><!-- /.table-responsive -->";
html += " <!-- .card-footer -->";
html += " <div class=\"card-footer\">";
html += " </div><!-- /.card-footer -->";
html += " </div><!-- /.card -->";
html += "</div><!-- /grid column -->";
return html;
}
function youtubeSubHtml(item) {
var html = "";
html += " <!-- tr -->";
html += " <tr>";
html += " <td class=\"align-middle text-truncate\">";
html += " <a href=\"javascript: void(0);\" class=\"user-avatar user-avatar-lg\"><img src=\"" + item.youtube_photo + "\"> </a>&nbsp;";
html += " <a href=\"https://www.youtube.com/" + item.youtube_account + "\" target=\"_blank\">" + item.youtube_name + "</a>";
html += " </td>";
html += " <td class=\"align-middle\"> " + item.youtube_account + " </td>";
html += " <td class=\"align-middle text-right\"> " + AppendComma(item.youtube_subscriberCount) + " </td>";
html += " <td class=\"align-middle text-right\"> " + AppendComma(item.youtube_avgViewCount) + " </td>";
html += " <td class=\"align-middle\">";
html += " <button class=\"btn btn-sm btn-icon btn-secondary\" data-uid=\"" + item.youtube_uid + "\" onclick=\"youtubeBtnClick(this);\"> <i class=\"fa fa-ellipsis-h\"></i></button>";
html += " </td>";
html += " </tr><!-- /tr -->";
return html;
}

View File

@ -98,6 +98,13 @@ $(document).ready(function () {
kolMedia_fansNum: RemoveComma($(this).find('td').eq(4).text().trim()) kolMedia_fansNum: RemoveComma($(this).find('td').eq(4).text().trim())
} }
if ($(this).find('td').eq(0).text().trim() == 'YouTube') {
if (kolMedia_accountName.substring(0, 1) != '@') {
err_msg += $(this).find('td').eq(3).text().trim() + " 此YouTube頻道資料有誤YouTube的帳號名稱第一碼應該為@字元\n";
}
}
mediaArray.push(item); mediaArray.push(item);
}); });

View File

@ -492,7 +492,7 @@ $(document).ready(function () {
function kolProjectPreview(obj) { function kolProjectPreview(obj) {
var uid = obj.getAttribute('data-uid'); var uid = obj.getAttribute('data-uid');
alert(uid); //alert(uid);
var formData = { var formData = {
method: "get", method: "get",